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

android开发-android的消息机制(Handler)源码解析

2017-10-01 18:45 483 查看
android的消息机制其实就是Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程

Handler的主要作用是讲一个任务切换到某个指定的线程中去执行

android规定访问UI只能在主线程中进行,如果在子线程中访问UI 那么程序会抛出异常。

ViewRootImpl对UI操作做了验证,这个验证的工作是由ViewrootImpl的checkThead

void checkThead(){

if (mThread != Thread.currentThread()) {

throw new CalledFromWrongThreadException(

"Only the original thread that created a view hierarchy can touch its views.");
}

}

所以必须在主线程中访问UI 但是android又不建议在主线程中做耗时的操作,否则导致ANR。

我们这时候就需要在子线程中进行耗时操作,获取完结果我们必须在主线程中显示ui

如果没有Handler 我们是无法玩成这样的工作的,系统提供Handler也是为了解决子线程中无法访问UI的问题

为什么系统不让子线程访问UI呢

因为android的UI控件不是线程安全的,如果在多线程中并发访问,准定会代理不可预期的问题

系统为什么不加上锁呢

缺点两个:1、加上锁会让UI访问的逻辑变的复杂。2、锁机制会降低UI访问效率,因为锁会阻塞一些线程的执行

所以最简单高效的方法就是采用单线程模型来处理UI,对开发者也不是很麻烦 只通过Handler切换一下UI访问的执行线程而已

Handler创建时会采用当前线程的Looper来构建内部的消息循环系统,如果当前的线程没有Looper那么就会报错的

因为Handler 发送、接受的消息 都是通过Looper来管理的,Looper里面有一个消息队列MessageQueue。

MessageQueue本质并不是队列,内部封装了一个单向链表数据结构来围护消息列表,单链表在插入和移除上有优势。它里面有两个方法,enqueueMessage和next,enqueueMessage负责向队列添加消息,而next负责取出消息并从消息队列里面移除。

Handler的post方法本质还是send,handler将Message消息投递到Handler内部的Looper中去处理。

这个send方法内部就是调用MessageQueue的enqueueMessage方法 将这个消息放入消息队列中,然后Looper发现有新消息到来 就会处理这个消息,这个Message中的target就是我们的handler,Looper会调用这个handler中的handlerMessage方法。

注意Looper是运行在创建Handler所在的线程(我们也可以给我们的Handler赋值一个Looper)

这样一来业务的逻辑就被切换到创建Handler所在的线程中去了。

无论消息是在哪个线程被添加到MessageQueue的,处理MessageQueue中的业务逻辑的还是最开始创建的线程!

Handler的工作需要Looper,没有Looper的线程就会报错,那么怎么开启一个Looper呢

Looper.prepare()为当前线程创建一个looper,而开启消息循环是looper.loop();

new Thread(){

 public void run(){
Looper.prepare();
Hanedler handler=new Handler();
Looper.loop();
}

}

Looper还提供了prepareMainLooper的方法,这个方法主要是给主线程,也就是ActivityThread创建Looper使用的,本质还是prepare方法,由于主线程的Looper比较特殊,所以Looper还提供了一个getMainLooper的方法,通过它可以在任何地方获取主线程的Looper

Looper还可以退出,调用quit或者quitSafely,他们区别是quite是直接退出,而quitSafely会先打一个退出的标记,然后等待消息都处理完毕之后才安全的退出

Looper退出之后,那么handler 发送send方法都会返回false

android主线程就是ActivityThread 主线程的入口方法为main,在main方法中系统通过Looper.prepareMainLooper() 来创建主线程的Looper以及MessageQueue,并通过Looper.loop()开启主线程的消息循环

比较好的文章

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