Android的消息机制概述

来源:互联网 发布:linux c fork 编辑:程序博客网 时间:2024/04/29 12:59

Handler产生的原因

Android的消息机制主要指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程,这三者实际上是一个整体,只不过我们在开发过程中接触最多的是Handler而已。Handler的主要作用是将一个任务切换到某个制定的线程中去执行,那么Android为什么要提供这个功能呢?因为Android规定访问UI只能在主线程中进行,如果在子线程中访问UI,那么程序会抛异常。验证工作是由ViewRootImpl的checkThread方法来完成的,如下所示:

void checkThread(){    if(mThread!=Thread.currentThread()){        throw new CallFromWrongThreadException(        "Only the original thread that created a view hierarchy can touch its views.");    }}

由于这点的限制,导致必须在主线程中方问UI,但是Android又建议不要再主线程中进行耗时操作,否则导致程序无法响应即ANR。因此为了解决在子线程中无法访问UI的矛盾,系统提供了Handler。
这里在延伸一点,系统为什么不允许在子线程中访问UI?因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预测的状态。那如果对UI控件加锁,缺点有两个:首先加锁机制会让UI访问逻辑变得复杂;其次锁机制会降低UI访问的效率,因为锁机制会阻塞某些线程的执行。鉴于这两个缺点,最简单且高效的方法就是采用单线程模式来处理UI操作。

Handler工作原理

Handler的使用方法这里就不做介绍,这里描述一下Handler的工作原理。Handler创建时会采用当前线程的Looper来构建内部的消息循环系统,如果当前线程没有Looper,那么就会报错,如下所示:

E/AndroidRuntime: FATAL EXCEPTION: Thread-8625                                                                    Process: com.kcgz.interview, PID: 29543                                                                    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()                                                                        at android.os.Handler.<init>(Handler.java:200)                                                                        at android.os.Handler.<init>(Handler.java:114)                                                                        at com.kcgz.interview.FibonacciActivity$MyThread.run(FibonacciActivity.java:48)

如何解决上述问题?其实很简单,只需在当前线程创建Looper即可,或者在一个有Looper的线程中创建Handler也行,具体在Android的消息机制分析中将详细介绍。

Handler创建完毕后,这个时候其内部的Looper以及Messagequeue就可以和Handler一起协同工作了,然后通过Handler的post方法将一个Runnable投递到Handler内部的Looper中去处理,也可通过Handler的send方法发送一个消息,这个消息同样会在Looper中去处理。其实post方法最终也是通过send方法来完成的,接下来主要看一下send方法的工作过程。当Handler的send方法被调用时,它最终会调用MessageQueue的enqueueMessage(msg)方法将这个消息放入消息队列中,然后Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable或者Handler的handleMessage方法会被调用。注意Looper是运行在创建Handler所在的线程中的,这样一来Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了,这个过程可以用下图表示:

handler工作过程

0 0