浅析Android中的Handler的消息传递机制
来源:互联网 发布:深入浅出node.js系列 编辑:程序博客网 时间:2024/05/16 14:06
###1.作用
由于主线程中做耗时操作会导致ANR异常,所以需要将网络请求等耗时操作放在子线程中来进行,但是由于在子线程中不能操作UI,所以需要将子线程中获取到的数据传递给UI线程更新.这样,Handler的机制就应运而生了.Handler的机制不仅仅能完成子线程与主线程的通讯,任何线程之间的通讯都可以用Handler.以下三张图由浅到深,根据自己喜好,自由选择看图理解:
图一:
图二:
图三:
###2.使用
1)在主线程中创建Handler,重写handleMessage方法.用该handler对象在子线程发送消息,然后在主线程中的handleMessage方法中处理消息 2)handler.post(Runnable runnable).
###3.组成:handler消息机制有四大组成部分,分别是:
1)Handler:用于发送消息和处理消息. 2)Message:用于携带数据和通知. 3)MessageQueue:用于存储消息,是单链表. 4)Looper:无限循环的轮训器,用于从MessageQueue中取出来消息,并交给Handler处理.
###4.源码分析:由于源码解析篇幅过大,这里仅从几个问题中说说源码.
(1)为什么我们在使用Handler的时候没有看到Looper和MessageQueue呢?
主线程默认通过Looper.prepareMainLooper方法准备了一个Looper对象,prepareMainLooper方法的具体实现如下:
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("ThemainLooper has already been prepared."); } sMainLooper = myLooper(); } }
实际上是先调用了prepare方法,然后myLooper的方法获取Looper对象赋值给sMainLooper.prepare方法的具体代码实现如下:
```private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); }sThreadLocal.set(new Looper(quitAllowed));}```
实际上就是new一个Looper对象,然后通过set方法将其存储带Threadlocal中,那我就猜测myLooper方法应该是通过get方法从ThreadLocal中获取Looper对象.我们看看吧.
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
果然,这样的化我们就获取到了Looper对象.但是MessageQueue对象呢?我们看看Looper的构造函数就知道了.
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
在构造函数中,new了一个MessageQueue对象,并赋值给Looper类的成员变量mQueue.
- (2).怎么实现由主线程向子线程传递数据?
要实现主线程向子线程中传递数据,那么我们必须在子线程中new一个Handle对象,然后用Handler发送消息给子线程.
但是在子线程new Handler对象的话会报错:没有Looper,不能new Handler.那么我们就必须先调用Looper.prepare方法准备一个对象,然后调用Looper.loop方法开始轮询.
prepare方法我们在第一个问题中分析了,会new一个Looper对象,然后通过set的方法将其存储到ThreadLocal中.
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; // 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) {//下面省略很多代码....}
该方法我虽然省略了很多的方法,但是已经足够理解原理了.
首先,第一行就通过myLooper()方法(在问题1中分析过),从ThreadLocal中取出Looper对象,并赋值给局部变量me.
然后me.mQueue得到MessageQueue对象,接着立马通过for(;;)开启一个无限循环,通过MessageQueue对象queue.next()取出消息.
所以通过调用Looper.prepare和Looper.loop()方法之后,我们就能通过Handler来实现主线程向子线程传递数据.
- (3).Looper是死循环,为什么不会引起ANR?
我们首先要找到调用Looper.prepareMainLooper和Looper.loop的地方,就是ActivityThread.java类的main方法.这也是应用程序的入口.
public static void main(String[] args) { ........ //创建Looper 和 MessageQueue Looper.prepareMainLooper(); ....... //开启无限循环轮询. Looper.loop(); throw new RuntimeException("Main thread loopunexpectedly exited"); }
那么问题来了,如果main方法中没有looper进行循环,那么主线程一运行完毕就会退出.这就完了.
所以我们可以得出结论,ActivityThread的main方法主要就是要做消息循环,一旦退出消息循环,那么你的应用也就退出了.
既然我们知道了死循环的重要性,那么为什么死循环不会造成主线程阻塞呢?
首先我们要了解造成ANR的原因:
(1)当前时间没机会得到处理.
(2)当前时间正在处理而没有计时完成.
因为Andriod是由时间驱动的,looper.loop不断接收时间\处理时间,每一个点击,触摸和Activity的生命周期都运行在looper.loop的控制下,如果它停止了,应用程序也就停了.如果某一个消息处理时间过长,那么下一次的用户的交互就得不到及时处理,就产生了卡顿,时间长了就会ANR.所以说明一个消息或者对消息的处理阻塞了looper.loop,不能说looper.loop阻塞了主线程.而且,主线程looper从消息队列中读取消息,当所有消息读完,主线程睡眠,当子线程再次往消息队列中发消息时,主线程将被再次唤醒.主线程被唤醒只是为了读取消息,读取完毕再次睡眠.因此,loop循环并不会对cpu有过多的消耗.
总结:只要looper.loop的消息循环和处理没有被阻塞,那么就不会引起ANR.
- (4).Looper 在取出消息后怎么能准确无误地将消息交给发送该消息的Handler 对象?
这里得从Handler的obtaineMessage开始分析,该方法实际调用的Message.obtain(this)方法.看看Message.obtain的源码:
public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; }
源码实现很简单,就是获取一个消息对象,再将Handler对象本身赋值给消息对象的target成员变量.也就是说,而Looper是通过MessageQueue的next方法取出消息的,通过取出这个消息的target属性我们可以得到发送该消息的Handler对象,然后looper对象就能将消息交给发送消息的Handler对象处理了.
- 浅析Android中的Handler的消息传递机制
- Handler消息传递机制浅析
- Android中的消息机制:Handler消息传递机制
- Android中的消息机制:Handler消息传递机制
- Android循序渐进 - 3.3 Handler消息传递机制浅析
- Android的Handler消息传递机制
- 解析Android的 消息传递机制Handler
- 解析Android的 消息传递机制Handler
- Android的Handler消息传递机制
- 解析Android的消息传递机制Handler
- Android Handler 的消息传递机制
- Android的Handler消息传递机制
- Android的Handler消息传递机制
- Android 的消息机制(Handler消息传递机制)
- Handler、Looper消息传递机制-----浅析
- 3.3 Handler消息传递机制浅析
- Android Handler消息传递机制
- Android Handler消息传递机制
- python爬虫学习(下)——爬虫代码实现
- noip2014寻找道路
- pid_t的类型
- JAVA WEB中利用@responsebody返回json
- 1062. Talent and Virtue
- 浅析Android中的Handler的消息传递机制
- 网络摄像机传输协议简析
- 总结29
- web前端面试知识点的一些总结
- PMP笔记:规划过程组检查事项
- 【Dongle】【软考】网络设备
- 课后题答案
- jenkins修改时区
- java工程师成长之路