您的位置:首页 > 移动开发 > Android开发

从源码分析Android中Handler的消息传递机制

2016-12-06 00:31 246 查看
 安卓开发人员开始研究安卓源码时,一般都从安卓的Handler消息传递机制开始。在讲安卓消息传递机制前我们要先讲为什么要有Handler一、什么要有Handler    在安卓中主线程是不能做耗时和阻塞操作的,我们需要将访问网络和耗时的操作放到子线程中去做,在子线程中获取了数据后经常有更新    主线程UI的需求,但安卓中子线程不能做更新UI的操作(准确的说是在安卓的审查机制建立后,子线程不能更新UI,只有子线程才能更新UI,值得注意的是,在安卓审查机制建立前,子线程是可以更新UI的),所以安卓中采用了Handler消息传递机制。可以将Handler看成是线程间的通讯工具。二、消息传递机制的大概流程    在了解流程前我们介绍Handler机制对应的四个对象:   Handler:发送Message,并且处理自己发送的Message    Message:消息--数据的载体,放入消息队列(MessageQueue)中,等待 Looper的轮询,之后交给对应的Handler处理Message中有 target  属性用来标记消息是哪个Handler发送的Looper:消息轮询对象,在UI线程创建时,就初始化出来,同时创建MessageQueue,并且启动轮询机制,等待消息。一个线程对应一个Looper   MessageQueue:消息队列,Handler发送出来的消息,首先放入该队列中,通过Looper的loop方法,取出来交给对应的Handler<通过Message中的target属性找到>处理。Looper初始化的同时,被创建,一个Looper对应一个MessageQueue (在主线程中创建的) 一个Looper的可以对应多个Handlaer
上面例子写了一个简单的主线程中handler的消息传递。
三、从源码分析消息机制的执行流程
首先我们来了解下Looper的几个方法:
    Looper.prepare() : 通过该方法创建了一个Looper对象,同时Looper对象中会创建了一个消息队列 MessgeQueen,并持有了当前的线程的引用   Looper.myLooper(): 获取Looper对象(在new Handler的时候会调用mLooper = Looper.myLooper(),如果mLooper==null 会报RuntimeExtion)    Looper.loop(): 开启一个死循环,有消息就取,没消息就阻塞,在那等,通过messgeQueen.next()不断的取消息,通过message.target.  dispathmesssge()分发消息(即处理消息)。现在我们来看下主线程中的Handler机制是如何被创建的。   首先我们得明白,安卓在创建主线程时会自动创建一个Looper,系统框架将所有在主线程中的操作封装成消息,然后在loop方法通过   messgeQueen.next不断的取消息(取消息,消息队列中没消息,可能阻塞,进入休眠状态,有新消息来了,通过管道流的机制,快速的   唤醒),通过dispathmesssge分发消息(处理消息,可能有耗时操作,可能ANR),所以耗时操作不能在主线程中做,而要在子线程中   做。   看Looper.prepare()的源码Looper的构造方法Looper.myLooper()Looper.loop()很关键,重点看到此Looper介绍完毕,继续往下看。
创建Handler对象 (前提是当前线程中已经创建了Looper对象)   在Handler的构造方法中会执行mLooper =Looper.myLooper()方法获取Looper对象(即对Handler绑定一个Looper对象),如果mLooper==null 会 报RuntimeExtion获取消息对象     Messge.obtain  从消息回收队列中取消息,没有就new Message()     Messge .recycle 将用完的消息放到消息回收队列中 下面代码就将回收的消息,放到回收队列的头部。发送消息(handler.sendMessge())    在发消息时会将当前的handler,赋值给了Messge的targte属性,将这个消息加入消息队列MessgeQueen中(如果是延时消息,按时间大小插入队列)  最终会执行sendMessageAtTime方法。通过loop()从消息队列中去取消息 并交给messge绑定的handler处理消息     在loop方法通过messgeQueen.next不断的取消息,通过message.targert.dispathmesssge分发消息,在handler的handMessge方法中执行        具体逻辑在子线程中也可以处理 (在主线程中发消息,在子线程中处理消息)     new MyLooperThread().handler2.sendMesssage(mssg);我们现在可以将多个线程绑定起来用,按一定的顺序执行现在我们来看子线程弹土司的问题子线程中可以弹土司,通过加Looper.prepare, 不提倡这么用,因为Looper.loop()是死循环,Acticity退出后,loop()中的资源得不到释放,造成内存的泄露。我们来看下Toast的源码:
我看到了Handler,看源码知道,Toast中 有这段代码 final Handler mHandler = new Handler(); new Handler()的提示要有一个Looper,
那么我们只需在Toast.makeTest().show()前加Looper.prepare(),之后加Looper.loop();就就可以在子线程中弹土司了。
最后我们重新看下Handler消息机制图:
获取和回收消息对象
消息的入列
感谢大家的阅读,希望对你有所帮助。
参考文章 
深入解析Handler机制 http://www.jianshu.com/p/02962454adf7

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐