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

解析Android如何利用Handler

2012-12-12 10:26 302 查看
本文解析Android如何利用Handler/Thread/Looper以及MessageQueue来实现消息机制的内部实现,了解了它的内部实现机理,对我们以后分析android模块有莫大的帮助。要了解handlerthread的工作过程,就要先分析looper,handler和Thread这三个类在消息处理机制中的作用,从名字就可以猜出个大概来,handlerThread自然会与Thread和Handler有关联,至于looper,那是一个消息处理循环主体。

其实HandlerThread就是Thread的子类,一个线程,在线程中进行looper的消息分发/处理循环,而handler主要用来传递消息,并被调用来处理消息,所以要清楚分析android的消息处理机制,要从三个方面来分别做分析:

1)android消息处理机制中相关类代码解析

2)android消息处理机制中各类之间关系

3)以线程的角度分析,使用该机制的技巧和注意的问题

为了方便参考代码和理清后面的关系,我以代码中重要部分穿插解释来进行说明。

(一)MessageQueue,looper和handler的职责及相互之间的关系。

(1)职责描述:

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Messagemsg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。这个类用于为线程执行一个消息循环。Looper的实例与一个线程绑定,但是线程默认是没有Looper对象与其绑定的,可以通过在线程上调用Looper.prepare()绑定一个Looper对象到当前线程,之后调用Looper.loop()方法执行消息循环,直到循环被停止(遇到一个target=null的消息,就会退出当前消息循环)。

在android中,Activity,Service属于主线程,在主线程中才能更新UI,如toast等。其他线程中不能直接使用更新UI,这时可以使用Handler来处理,Handler可以在Activity和Service中定义。
熟悉Windows编程的朋友可能知道Windows程序是消息驱动的,并且有全局的消息循环系统。而Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制。实际上谷歌参考了Windows的消息循环机制,也在Android系统中实现了消息循环机制。Android通过
Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环)。
Android系统中Looper负责管理线程的消息队列和消息循环,具体实现请参考上面的Looper的源码。可以通过Loop.myLooper()得到当前线程的Looper对象(这是我们一再强调的重点),通过调用Loop.getMainLooper()可以获得当前进程的主线程的Looper对象。
前面提到Android系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper)。特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环功能,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。

Activity是一个UI线程,运行于主线程中,Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper)。详细实现请参考ActivityThread.java文件。
Handler的作用是把消息加入特定的(Looper)消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建。
一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在主线程中处理了。因为主线程一般负责界面的更新操作,并且Android系统中的weget不是线程安全的,所以这种方式可以很好的实现Android界面更新。在Android系统中这种方式有着广泛的运用。
那么另外一个线程怎样把消息放入主线程的消息队列呢?答案是通过Handle对象,只要Handler对象以主线程中创建,并用主线程的的Looper创建,那么调用
Handler的sendMessage等接口,将会把消息放入队列都将是放入主线程的消息队列(这是handler与looper共用一个MessageQueue的结果)。并且将会在Handler主线程中调用该handler
的handleMessage接口来处理消息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: