《代码里的世界》
用文字札记描绘自己 android学习之路
转载请保留出处 by Qiao
http://blog.csdn.net/qiaoidea/article/details/45115047
【导航】
Android更新Ui的几种方法和见解 android更新ui基本常用方法
Android更新Ui进阶精解(一) android ui线程检查机制
Android更新Ui进阶精解(二) android 线程更新UI机制
1.回顾
第一篇讲了对Ui线程更新的方法和见解,然后接着讲了线程检查机制,这里来详细分析下更新Ui的核心——Android中消息系统模型。当然,这里要讲的其实也已经不再简简单单地是更新Ui的范畴了。不过还是很值得学习和分析一下。另外,其实网上关于这方面的讲解也有很多了,本篇也是综合整理并用自己的理解加以描述和概括。同时也感谢有更高造诣的大大能予以批评指正。
提炼
Android中的消息机制主要有如下几个要点,这里也着重围绕这些内容来讲解:
1. Handler 调度消息和runnable对象在不同线程中执行相应动作。
2. Looper消息泵,用来为一个线程开启一个消息循环
3. MessageQueue 遵循FIFO先进先出规则的消息队列,以链表形式存取Message,供looper提取
(为了深入了解,已从源码从提取这几个类
Handler/Looper/MessageQueue/Message .java 方便新手下载查看)
2.分析
为了方便分析,借用一下找到的模型图综合看一下:
首先在一个线程中初始化一个looper并prepare(准备),然后创建该looper对象的处理对象Handler,接着当需要交互变更时,可以在其他线程(或自身线程)中使用handler发消息至该消息队列MessageQueue,最后looper会自动有序抽取消息(没有消息则挂起),交给handler执行消息处理逻辑。
Orz,我的概念描述还是一塌糊涂,还是转代码说明吧:
比如我们有个线程专门负责一类处理逻辑,并且只允许该线程来处理这类逻辑,那么我们怎么做到呢?
- 在一个线程里边定义一个Looper
1
Looper.prepare(); //稍微有点儿多,详细见下文
2.定义一个处理消息的Handler
1 | handler = new Handler(){ |
3.启动looper,并开始工作,轮询消息
1 | Looper.loop(); //详细见下文 |
4.在其他线程将要处理的数据data或回调对象callback以消息Message模式通过Handler发至该消息队列MessageQueue1
handler.sendMessage(msg)
5.Looper的loop()方法会从消息队列中取到该消息并唤醒处理逻辑1
2
3
4
5
6
7
8
9//即loop()方法中的代码
for (;;) { //显然这个死循环一直在等待消息到来并处理
Message msg = queue.next(); // 取一条消息
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg); //调用消息绑定的handler执行处理逻辑
//other code....
}
6.handler跳转到执行处理逻辑的过程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public void dispatchMessage(Message msg) {
if (msg.callback != null) { //如果有回调,则调用
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//调用回调方法
private static void handleCallback(Message message) {
message.callback.run();
}
```
<!--more-->
以上便是整个消息系统的过程,后边我们会逐个分析精讲。
---
### ***3.回到我们更新UI讲解***
在ActivityManagerService为Android应用程序创建新的进程并启动activity时候,主线程ActivityThread首先被创建。该进程 Process.java@start("android.app.ActivityThread",...)会加载执行ActivityThread的静态成员函数main,打开该方法:
``` java
public static void main(String[] args) {
//other code.. 我们只看有用的部分,其他暂略过
Looper.prepareMainLooper(); //准备looper,注,绑定的为当前主线程
ActivityThread thread = new ActivityThread();//开启一个新ActivityThread线程
thread.attach(false);//最后执行到activity
//other code..
Looper.loop(); //启动looper
这个静态函数做了两件事情,一是在主线程中创建了一个ActivityThread实例,二是通过Looper类使主线程进入消息循环。
然后,代码经过一系列逻辑( ActivityThread.attach->IActivityManager. attachApplication -> attachApplicationApplicationThread.scheduleLaunchActivity ->… ->ActivityThread.performLaunchActivity ),最终会调用activity的attach方法。
我们打开activity类。可以看到,它定义了uiThread和Handler参数1
2
3
4ActivityThread mMainThread;//对应上边的ActivityThread线程
private Thread mUiThread;//主Ui线程
final Handler mHandler = new Handler();//这个handler就是activity用来处理Ui的了。我们自己定义的handler其实等于重新定义了这个mHandler;
我们来看activity的attach方法:1
2
3
4
5
6
7
8
9
10final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, IVoiceInteractor voiceInteractor) {
mUiThread = Thread.currentThread();//当前主线程Ui线程
mMainThread = aThread; //对应上边的ActivityThread线程
}
所以,当我们要更新UI的时候,都会用到sendMessage,比如使用runOnUiThread,来看下这个方法1
2
3
4
5
6
7
8
9
10public final void runOnUiThread(Runnable action) {
/**
*如果当前线程不为Ui主线程则使用定义好的mHandler
*/
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
打开post方法:1
2
3
4public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
还是熟悉的配方,还是熟悉的味道。。封装成消息,然后发送出去。好,我们再回头看看最初第一篇文章里的四种方法:
1.new 一个handler来 sendMessage();
2.利用new handler来post
不过是把上边已经定义好Activity的mHandler重新定义了一遍,然后封装成消息发送出去;
3.runOnUiThread
同样不过是用了Activity的mHandler发送消息;
4.view.post
稍微看一下代码:1
2
3
4
5
6
7
8
9public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
}
对于AttachInfo应该不算陌生吧,附加view到Activity的时候会把activity的一些属性附加给AttachInfo,这里同样调用取得mHandler然后再post。。绕了一圈又回来了。
综上看来,整个UI更新机制其实就是Android消息系统模型的一个简单实现。至此,我们的更新UI部分也算讲完了,那么作为补充部分,还是从源码上完整细致的过一下整个消息系统模型吧。
4.精解
这里通过剖析源码来理解各部分的具体实现,再结合前面讲的内容加以融会贯通,便于深入理解最终达到在不同场景的熟练使用。
我们将按照顺序来逐个查看。
首先说说消息对象,毕竟其他类操作的最基本元素也都是它。
4.1 Message
1 | public final class Message implements Parcelable { |
既然提到消息池又在前面讲了利用obtain()节省内存资源,那么我们就看下这个obtain()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
*从消息池中返回一个新的消息实例,避免我们通常情况下分配新对象。
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
然后就是基于此方法的一系列运用:先调用obtain()方法,然后把获取的Message实例的 各种参数赋值传参。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34//取一个消息对象,把已存在的消息内容赋值过去
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
//调用obtain并赋值,不再一一列出
public static Message obtain(Handler h) {//..}
public static Message obtain(Handler h, Runnable callback) {//..}
public static Message obtain(Handler h, int what) {//...}
public static Message obtain(Handler h, int what, Object obj) {//...}
public static Message obtain(Handler h, int what, int arg1, int arg2) {//...}
然后就是回收释放recycle,它返回一个消息池实例。释放之后将不能再使用此方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
//清空所有数据
void clearForRecycle() {
flags = 0;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
when = 0;
target = null;
callback = null;
data = null;
}
//拷贝消息内容
public void copyFrom(Message o) {
this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
this.what = o.what;
this.arg1 = o.arg1;
this.arg2 = o.arg2;
this.obj = o.obj;
this.replyTo = o.replyTo;
if (o.data != null) {
this.data = (Bundle) o.data.clone();
} else {
this.data = null;
}
}
后边就是get和set方法以及Parcelable 的读写。
4.2 Looper
先看他所定义的属性:1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Looper {
private static final String TAG = "Looper";
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;//唯一对应一个主线程的looper静态实例
final MessageQueue mQueue;//消息队列
final Thread mThread; //当前绑定线程
volatile boolean mRun; //是否允许退出
private Printer mLogging;//日志打印
//....各种方法体....
}
通常操作系统都为线程提供了内部存储空间,一个线程对应一个内存空间,因此这里很方便的为一个线程定义唯一对应的looper实例:ThreadLocal< Looper > 这个有点类似C中申请内存大小 malloc(sizeof Looper),或者我们可以简单理解为只作用于当前线程的*new Looper.
而sMainLooper是当前应用程序的主线程looper,区别是适用于主线程。
我们再看他的构造方法:1
2
3
4
5private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
此构造方法是私有的,即不允许在外部实例化,这样通过单例模式保证外部从该线程取得looper唯一。另外它主要初始化了mQueue 、mRun 和 mThread 几个属性,并绑定了当前线程。找一下它调用实例化的部分:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//重载,主要看下边的prepare(boolean quitAllowed)方法
public static void prepare() {
prepare(true);
}
/**
*初始化当前线程作为Looper并存为本地变量,
*并由此来创建handler和处理程序
*
*@quitAllowed 是否允许退出(循环取消息)
*通过调用loop()和quit()来开启和结束循环
*/
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { //保证一个线程唯一对应一个Looper
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));//在线程中初始化一个实例
}
sThreadLocal的get和set,负责在内存中存取与线程唯一对应的looper。
同时我们会注意到有两个方法prepareMainLooper和getMainLooper:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
*初始化当前线程作为Looper并作为android应用的取消息逻辑,
*是由当前运行环境来创建,不需要手动调用
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) { //加锁,保证实例化唯一一个looper
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* 返回当前应用程序主线程的looper实例
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
这部分是共应用程序初始化的时候调用的,我们一般用不到,不过也可以看出只是初始化了主线程的looper。
好的,基本的初始化工作也已经完成了,来看该类中的核心部分,循环取消息的loop()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48/**
* 启动队列的循环取消息操作,直到调用quit()退出
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 确保当前线程是本地进程的唯一标示
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//开始循环取消息操作
for (;;) {
Message msg = queue.next(); //取下一条消息
if (msg == null) {
// 如果消息队列没有消息则挂起
return;
}
// 打印日志部分
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//调用消息处理逻辑(回调和执行handler处理)
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// 确保在处理消息逻辑时当前线程并没有被打断
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();
}
}
基本都有备注,不用过多解释了。msg.target.dispatchMessage前面已经讲过,后便可能会在拉出来遛遛。
其他再就是基本的get和打印和异常捕获相关的了,有兴趣的可以自己去看一下。
4.3 MessageQueue
类的描述简要翻译一下:
MessageQueue是一个低级类,负责维护一个需要被Looper派发处理的消息列表。其消息对象是通过hanlder绑定到looper上的,而不是直接添加到消息队列中去的。
其实即MessageQueue只是一个消息队列,提供给handler加入和Looper取出消息操作,这两个接口分别是 enqueueMessage(Message msg, long when) 和 next()。
先看属性:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class MessageQueue {
// 消息队列是否可以退出
private final boolean mQuitAllowed;
Message mMessages;//message实例(类似链表)
//存放 IHandler的list和数组
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuiting; //Thread是否退出
// 判断next()是否因一个非零的超时pollOnce()而处于阻塞等待
private boolean mBlocked;
//标志位,表示阻碍是否是由于消息的空target(handler)引起
private int mNextBarrierToken;
//native code部分略过
@SuppressWarnings("unused")
private int mPtr; // used by native code
private native void nativeInit();
private native void nativeDestroy();
private native void nativePollOnce(int ptr, int timeoutMillis);
private native void nativeWake(int ptr);
我们来了解一下MessageQueue内部定义的IdleHanlder接口:
这是一个提供给线程,用来阻塞等待更多消息的回调接口。1
2
3public static interface IdleHandler {
boolean queueIdle();
}
queueIdle()方法会在该消息队列处理完所有消息并且不会有新消息时候调用,返回true则该闲置idlehandler保持活跃,否则(false)移除该idleHandler。当然,如果还有消息在队列中等待,并且这些消息是在接下来的时间才被处理,那么queueIdle()也会被调用。
对于添加和移除idlehandler我们简要略过.1
2
3
4
5
6
7
8
9
10
11
12
13
14public final void addIdleHandler(IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
public final void removeIdleHandler(IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
取消息next()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 final Message next() {
int pendingIdleHandlerCount = -1; //空闲的idleHandler个数
int nextPollTimeoutMillis = 0;//下次取消息的时间
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();//刷新等待命令
}
nativePollOnce(mPtr, nextPollTimeoutMillis);//更新下次取消息时间
//取消息锁
synchronized (this) {
if (mQuiting) {//线程正退出
return null;
}
// 尝试取下一条消息并返回
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
//查找下一个不为空且不是异步的消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 如果当前消息并没到指定时间,则等待nextPollTimeoutMillis 后执行取操作
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 取一条消息
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// 当没有消息时,下次取操作的时间间隔设置为-1
nextPollTimeoutMillis = -1;
}
// 如果是首次闲置,则获取需要运行的空闲hanlder数量。闲置的hanlder只有在消息队列为空或者当前时间没有消息被处理的时候等待
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 如果没有闲置handler等待,则消息队列进入阻塞等待
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 运行闲置handler,我们只有在首次迭代时运行下边这段代码
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; //释放闲置hanlder
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//重置闲置handler数量
pendingIdleHandlerCount = 0;
//当回收闲置handler时候可能有新消息被放进来,所以更新下次取消息时间重新执行
nextPollTimeoutMillis = 0;
}
}
插入消息enqueueMessage(Message msg, long when) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48final boolean enqueueMessage(Message msg, long when) {
//如果消息正在被使用或者消息的处理handler为空,都会抛异常
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw new AndroidRuntimeException("Message must have a target.");
}
boolean needWake;
synchronized (this) {
if (mQuiting) {//如果线程已退出,则抛出异常
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
}
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
// 如果消息处理时间等于0或者小雨队列头的处理时间,则将该消息插至消息队列头
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//将消息插入对位,通常我们不需要唤醒事件,除非消息队列处在阻塞状态并且这条消息是队列中最早的异步消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}
删除消息removeMessages() 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123final void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycle();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycle();
p.next = nn;
continue;
}
}
p = n;
}
}
}
final void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycle();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycle();
p.next = nn;
continue;
}
}
p = n;
}
}
}
final void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycle();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycle();
p.next = nn;
continue;
}
}
p = n;
}
}
}
```
#### *4.4 Handler*
Handler是和线程的MessageQueue相关联的Runable对象,用于发送和处理消息。Handlerg和线程及线程的MessageQueue是一一对应的,即每个Handler实例关联一个单一线程和该线程的messagequeue。当您创建一个Handler时,它就绑定到创建它的线程以及对应的消息队列。使用该handler将发送消息到对应消息队列,并由Handler处理取出的消息。
**简单来说,handler主要做了两件事:**
- 将要处理的数据消息或runnable以消息形式放入消息队列,在指定时间处理;
- 保证运行在多个线程中得消息对象能够在指定线程中被有序处理。
##### ***1.先看属性变量***:
``` java
public class Handler {
/*
* 标志位,用来检测那些继承于它但不是静态的匿名类、本地类或成员类,这些类可能会导致内存泄露。
*/
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
}
2.再看构造方法:
1 | public Handler() { |
最后都执行的是这两段构造方法:
- Handler(Callback callback, boolean async)
- 当标志位为true,检测到可能造成内存泄露的类时抛出异常
- 得到当前线程的looper初始化其属性变量
- Handler(Looper looper, Callback callback, boolean async)
- 由传入的参数初始化属性变量
1 |
|
3.接着看它的生成Message:
产生消息的方法obtainMessage()是间接调用Message的obtain()方法,尝试从消息池中取已有message实例,便于高效和重复利用。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 //基本类似,不再一一列举
public final Message obtainMessage()
public final Message obtainMessage(int what)
public final Message obtainMessage(int what, Object obj);
//利用Message的obtain方法构造消息
public final Message obtainMessage(int what, int arg1, int arg2, Object obj){
return Message.obtain(this, what, arg1, arg2, obj);
}
//将runnable封装成消息
private static Message getPostMessage(Runnable r)
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
4.然后看它的send消息的过程:
handler有提供post(runnable)和sendMessage(message)两种方法。post其实就是通过上边的getPostMessage方法将runnable对象封装成消息发送至消息队列。这些发送消息的方法有:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
//上述方法都调用sendMessageDelayed()方法
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
这些方法都转入了sendEmptyMessageAtTime这个方法中去1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
//还有这个方法
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
sendMessageAtTime在指定时间发送消息,对消息进行有序排队。调用enqueueMessage()方法,该方法又调用消息队列的queue.enqueueMessage()方法。在指定时间更新消息时序。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
```
发送消息还有一个方法,将消息放在队列首并立即取消息。使用方法sendMessageAtFrontOfQueue
``` java
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
最后looper循环取消息并调用handler的处理方法dispatchMessage 和handleMessage1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//当message的callback不为空的时候,调用handleCallback
private final void handleCallback(Message message) {
message.callback.run();
}
//这里是个空方法需要子类定义处理逻辑
public void handleMessage(Message msg) {
}
当我们实例化一个handler时候,handler会通过mCallback接口来回调我们的handleMessage方法,看一下这个接口:
1 | public interface Callback { |
5.综述
以上便是Android中的消息机制的几个核心部分内容和源码概括完了。详细读到这里多少也对整个体系有了点深入了解吧。当然,个人叙述相对有些混乱,建议感兴趣的朋友可以在sdk\sources目录下找到相应源码查看具体详细。
作为补充还是把对应的Handler Looper MessageQueue 和 Message 的.java文件放上来,方便不会关联源码的朋友查看。
Handler/Looper/MessageQueue/Message .java 文件