说到消息机制就要先了解异步消息处理,异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。而android中的消息机制使用的是handler+message+looper.
- 首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法,最后执行消息对应的handler的handmessage()方法.只有在主线程创建handler,handmessage方法才是运行在主线程中,才可以更新UI,否则也只能用来接收消息
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。也可以指定一个Looper实例.我们自定义一个handler就是要和一个looper绑定,这样这个handler就可以将消失发送到指定的looper队列中.,必须在子线程类的run方法中创建hander才会是默认绑定子线程的looper,否则都是默认绑定的主线程的Looper.不在run中不算线程,开启线程调用的start方法实际上就是调用run方法
4.平常我们在使用的时候就是利用handler.sendMessage将Message发送到Looper的队列中去即可,Message最好用Message.obtain获取,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。
5.在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法,所以我们在主线程不用手动的调用了
上面只是对消息机制的原理的一个概述,下面我就说说我对消息机制更新UI的理解,
1.我以为子线程是不能更新UI的,但实际上不是这样的,在线程中更新UI时会调用ViewParent.invalidateChild()方法检查当前的thread是否是Mainthread。但是,ViewRootImpl这个类是ViewParent的实现类是在activity的onResume()方法中创建的。就算在子线程中更新UI,只要在ViewRootImpl创建之前更新UI就不会报异常.
2.android中不让子线程更新UI是为了解决多线程并发问题, 因为如果子线程可以更新UI就有可能造成界面混乱.
3.消息机制只是发送消息,我们是要根据发送的消息在handmessage做相应的操作,比如UI的更新,而消息机制是不能直接更新UI的.
4.无论如何子线程,都只是将更新UI的消息发送到主线程的消息队列中,然后调用主线程中handmessage方法,这样就将子线程的操作移到了主线程就可以更新UI了.而如果handler是定义在子线程中也还是不可以更新UI的
最后在说下子线程更新UI常用的方法
1.handler+message
2.runOnUiThread
3.handler或者View的post方法,但是要注意post方法中runnable是运行在主线程中的,所以不能执行耗时的操作.