Android 子线程更新UI机制


子线程更新界面,目前我所知道的方法有两个,一个是用Handle,一个是用BroadcastReceiver。本章主要讲述子线程是如何通过Handle更新界面的。

使用Handle更新界面的条件

一条线程里要有一个handle,一个Looper,一个MessageQueue,一个Message。 

下面再来看看这些条件怎么具备的

当app启动的时候,Android会为程序创建一条可以用来更新界面的线程,称为UI线程。界面更新的工作只能在这条线程里完成。

先来看看Activity的源码,看源码得知,Activity里new了一个全局的handle对象mHandle


我们再来看看handle的源码,源码里有一个handleMessage方法


我们就是在这个方法里更新UI的。这个方法有个参数,就是Message对象。这个msg是从哪里来的呢?请给我一首歌的时间,我先把sendEmptyMessage拉出来晒晒。


当我们通过handle调用senEmptyMessage方法时,其实就是在调用sendEmptyMessageDelayed方法。sendEmptyMessageDelayed方法生成了一个Message对象,还调用了SendMessageDelayed方法。SendMessageDelayed方法里做了什么,不急,我们先去看看obtain方法做了什么。


obtain方法返回一个Message对象m或者new一个Message对象,而m又是等于sPool的,sPool又是什么呢?


sPool也是一个Message对象,obtain方法意思就是当前没有Message时,new一个,有就返回当前的。

好啦,现在知道handleMessage方法里的Message对象怎么来的了,知道怎么发消息的,那发的消息怎么跑到handleMessage方法里的呢?别急,还有两个元素没提,那就是looper和messagequeue。前面有个方法没有进去看,现在我们来看看SendMessageDelayed方法。


sendMessageDelayed方法继续调用了另一个方法sendMessageAtTime,我们在看看这个方法


看见没,MessageQueue出现了。那么mQueue是什么,什么时候实例化的。


mQueue是在Handle的构造方法里实例化的,有心的自己看看源码。到这里,不知道看官明白没,所有的对象都一 一指向了系统生成的对象。

Activity启动后会自动生成一个线程,一个handle,一个Looper,一个MessageQueue,一个Message,开发人员要做的就是把我们声明的引用指向或者通过方法调用这些对象就可以了(handle除外)。

总结:我们自己在Ui线程new一个Handle,子线程里通过这个handle把Message发到UI线程里的MessageQueue里,相对应的Looper会循环在MessageQueue里读消息,读到消息后通知相应的handle来处理消息,哪个handle发的消息就通知哪个handle。

handle里有个封装好的更新Ui的方法


这个方法其实就是在调用

sendMessageDelayed方法。要在子线程才能用。如果run方法里没有更新Ui,在Ui线程使用也不会报错,不过这样就没有什么意义了。

Handle更新UI在整个Android都很重要,Android很多方法和类或者第三方的代码更新Ui,只要你点进去看源码,就会发现大部分是在用handle,handle就到这里了。关于发广播到Ui线程更新Ui,以后再写。