android(七)Looper Handler分析
一。总结
Looper有一个MessageQueue,用于封装消息循环。 Handler封装了消息投递,消息处理等的辅助类
二。分析
1.从Looper的用法开始分析
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); //(1)调用prepare
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop(); //(2)进入消息循环
}
}
(11)prepare做了什么?
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper()); //(12)构造一个Looper,设置到线程本地变量中
}
(12)构造Looper对象
private Looper() {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread(); //得到当前线程
}
所以由(12)可知,prepare把Looper对象保存在线程本地变量中。巧妙地把Looper和调用线程关联起来。
2.Handler-MessageQueue-Looper,三者构成了死循环+消息通信的模型
public static void loop() {
final Looper me = myLooper(); // (21)取得线程本地变量Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; // 取出Looper中的queue
// Make sure the identity of this thread is that of the local process, and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg); //Handler target; 参照下面的dispatchMessage方法
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
}
public static Looper myLooper() { //(22)返回线程本地变量Looper
return sThreadLocal.get();
}
所以由(21)、(22)可看出loop()处理本线程消息队列中的消息。
三。Looper, Message,Handler之间的关系
1.Message中有个Handler,指定这个Message由哪个Handler处理
Handler target;
2.分析Handler成员变量
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
3.Handler默认构造函数
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName());
}
}
mLooper = Looper.myLooper(); //(31)获得调用线程的Looper
if (mLooper == null) {
throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //(32)获得Looper中的消息队列
mCallback = null;
}
4.Handler的另一个构造函数
public Handler(Looper looper) { //(33)传入某个线程的Looper
mLooper = looper;
mQueue = looper.mQueue; //(34)获得Looper中的消息队列
mCallback = null;
}
由上可知,Handler中的MessageQueue都会指向Looper中的消息队列。
5.There are two main uses for a Handler:
(1) to schedule messages and runnables to be executed as some point in the future;
(2) to enqueue an action to be performed on a different thread than your own.
Handler只有一个消息队列,即MessageQueue。通过post()传进去的Runnable将会被封装成消息对象后传入MessageQueue。当Looper轮询到该线程时,并不会单独开启一个新线程,
而Runnable仍然在当前Looper绑定的线程中执行,Handler只是调用了该线程对象的run()而已。通过post()将Runnable提交到主线程的Looper中可以实现UI的更新。
51.sendMessage
public boolean sendMessageAtTime(Message msg, long uptimeMillis){
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this; //(41)把处理这个message的Handler设为自己
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
2.post
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; ///*package */ Runnable callback; 将Runnable封装成消息对象
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
6.消息处理
public void handleMessage(Message msg) { //子类要重写的方法
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) { //如果msg本身有callback
handleCallback(msg);
} else {
if (mCallback != null) { //如果handler本身有callback
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); //最后交给子类处理
}
}
7.msg的Callback
private static void handleCallback(Message message) {
message.callback.run(); //直接调用Runnable的run方法,也就是说不是新建线程来执行
}
android(七)Looper Handler分析的更多相关文章
- Android的消息循环机制 Looper Handler类分析
Android的消息循环机制 Looper Handler类分析 Looper类说明 Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在ru ...
- 转 Android的消息处理机制(图+源码分析)——Looper,Handler,Message
作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种 ...
- 【转】android的消息处理机制(图+源码分析)——Looper,Handler,Message
原文地址:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments 作为一个大三的预备程序员,我学习 ...
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解android ...
- android的消息处理机制(图文+源码分析)—Looper/Handler/Message[转]
from:http://www.jb51.net/article/33514.htm 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.andro ...
- Android -- 消息处理机制源码分析(Looper,Handler,Message)
android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...
- android的消息处理机制——Looper,Handler,Message
在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...
- (转)Android消息处理机制(Handler、Looper、MessageQueue与Message)
转自 http://www.cnblogs.com/angeldevil/p/3340644.html Android消息处理机制(Handler.Looper.MessageQueue与Messag ...
- android的消息处理有三个核心类:Looper,Handler和Message。
android的消息处理机制(图+源码分析)——Looper,Handler,Message 作为 一名android程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设 ...
随机推荐
- .NET批量数据入库
/// <summary> /// 批量写入数据库 /// </summary> /// <param name="urlInfo">Url类& ...
- 如何创建圆角 UITextField 与内阴影
本文转自http://www.itstrike.cn/Question/9309fbd6-ef5d-4392-b361-a60fd0a3b18e.html 主要学习如何创建内阴影 我自定义 UITex ...
- iOS - Share Extension
1. 学 Share Extension 之前 先了解一下iOS的App Extension 2.1 创建Share Extension扩展Target ** 注:扩展不能单独创建,必须依赖于应用工程 ...
- drizzleDumper的原理分析和使用说明
https://blog.csdn.net/qq1084283172/article/details/53561622 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...
- 利用NtQuerySystemInformation函数遍历进程,遍历线程,获取线程挂起或运行状态
版权声明:专注于计算机网络安全学习 https://blog.csdn.net/u011672712/article/details/51586030 1 2 3 4 5 6 7 8 9 10 11 ...
- Linux记录用户shell命令
在/etc/profile中添加下面内容: export LC_ALL=C TMOUT=3600 HISTFILESIZE=2000 HISTSIZE=2000 HISTTIMEFORMAT=&quo ...
- 二、K3 WISE 开发插件《 工业单据老单客户端插件事件、属性、方法》
===================== 目录: 1.插件事件说明如下 2.插件属性说明如下 3.插件方法说明如下 ===================== 1.插件事件说明如下: 序号 事 ...
- 【HIbernate异常】could not initialize proxy - no Session (已解决)
异常信息: org.hibernate.LazyInitializationException: could not initialize proxy - no Session 解决方法: 用 get ...
- jQuery事件处理(三)
继续了解jQuery对浏览器兼容的处理 1.keyHooks对键盘按键的封装 keyHooks: { // 一些键盘相关的属性 props: "char charCode key keyCo ...
- Python pyQt4/PyQt5 学习笔记4(事件和信号)
信号 & 槽 import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QWidget,QLCDNumber,QS ...