在android中,UI线程和其他子线程之间传递数据一般要用到handler和looper,那么其工作原理是 什么呢?

我们通用的方法是:在UI线程中创建handler--将handler传递到子线程中--在子线程中sendmessage---消息被加载进looper的message队列中--在UI线程中handlemessage

该方法我们可以用一个比喻:

Handler在某个国家(主looper线程)实例化以后,就在该国家建立一个机构,该机构会派遣人员(handler)到某个子线程,该人员身上带着消息鸽子(obtainmessage),这些消息鸽子的目的地(target)自动锁定那个handler机构,当收集到消息后,将消息鸽子放出去(sendmessage),鸽子飞到后会把消息放进消息池(messageQueue)中,这个国家的looper会执行loop()方法,不停从消息池中拿到消息交给机构,机构得到消息之后,有handleMessage()方法可以处理这些消息;


但是,我们能不能在子线程中创建handler,实现UI线程的修改呢?
当然可以!直接派遣looper到子线程,跟那里的handler绑定(通过handler的构造方法将looper传进去),把在子线程实例化的handler变成主线程直属handler来为自己服务,这样在子线程的handleMessage方法中执行UI线程的修改也是不会报错的。


那么,到底是什么机制,使这两种方法都能行得通?

通过研究android源码之  handler.java  ~~ Looper.java,我们可以得到以下结论:

handler在哪里创建是没有关系的,重要的是handler发送的message到达了那个looper的消息队列,不管通过什么方法,只要让handler发送的消息到达UI线程Looper的消息队列,就能实现对UI线程的修改!

要理解上面这句话,首先要了解这么几个概念:

1,一个普通Thread不能创建handler的,需要在该线程的run()方法中执行Looper.papare(),将该线程变为looperThread。(UI线程自动执行了looper.papare和looper.loop()方法,所以UI线程本身就是looper线程)
2,一个looperThread只能有一个looper,一个looper绑定一个messageQeue;
3,一个looperThread可以用多个handler;

handler跟Thread没有关系,它跟looper绑定,具体绑定那个looper,就要看用的那个构造方法,如果用的是new Handler()这个构造方法,会默认绑定它所在线程的looper和消息队列(handler.java源码中描述为:mLooper = Looper.myLooper();mQeue = mLooper.Qeue),如果用的是new Handler(Looper looper)的构造方法,就会与传进去的那个looper绑定;

绑定某个looper,当sendMessage时就会向那个looper绑定的消息队列(messageQeue)里发送消息。

(那么handlerMessage()这个方法是在哪里执行的呢?)

Looper里有个死循环方法loop(),不断检查与其绑定的消息队列里的消息,一条条按顺序拿出,并执行msg.target.dispathMessage(msg),这个dispathMessage本身调用的就是handleMessage()方法,所以,handlerMessage本质上是在Looper的死循环里处理的,只要这个Looper属于UI线程,那么程序就不会报错,可以顺利执行。


====================================================================================================================================

上面描述的是子线程操作UI时报错的解决办法,那么子线程操作UI就一定会报错崩溃吗?

不!首先我们要了解系统为什么会崩毁并报错,是系统本身有一个判断机制,当执行到layoutRequset  时,只有判断到parentLayout != null系统才会判断并抛出异常,导致错误;

其实,在oncreate()方法中执行对UI控件值的修改是可以的,因为此时activity的生命周期才刚开始,parentLayout还没创建和绘制,其值是null,所以“监控失效”,所以不会抛错和崩溃,并且控件的属性值会被正常修改。