Android中的UI线程(主线程)不是线程安全的,所以无法在非UI线程中更新UI.
解决方法是使用Handler+Message。Handler默认会有一个当前线程的引用(如UI线程),非UI线程可以通过Handler的引用,向UI线程发送Message,
UI线程在收到Message后就可以在当前线程里更新UI.
消息系统
一般UI线程必须建立自己的消息循环系统,然后通过消息系统不断的获取消息更新界面来进行用户交互. 一般消息系统包括以下几部分:
- 消息原型(Message类)
- 消息队列(MessageQueue)
- 消息循环(Looper负责)
- 消息发送(Handler负责)
- 消息获取(Looper负责)
- 消息派发(Looper负责)
- 消息处理(Handler中的handlerMessage)
Android的UI线程也同样要建立这么一个消息系统。
Android消息系统框架:
![](https://i-blog.csdnimg.cn/blog_migrate/3e38c2a5dcd03b057791ba38f0c85eee.jpeg)
Message和MessageQueue
它们用来实现基本的消息队列。这里需要注意的是Message拥有一个Handler的引用,也就决定了该Message从MessageQueue取出时是通过
这个Handler进行派发处理的。
Looper
Looper是实现消息循环的,所以需要有Thread的引用和MessageQueue来循环获取和存放Message。这样就实现了消息循环和消息获取了。
一个Thread默认是没有消息循环的,也就没有Looper,要实现消息循环可以通过Looper.prepare( )创建,通过Looper.loop()启动。
Handler
要更新UI线程主要是跟这个类打交道,其它基本很少用到。
功能一:消息发送
Handler维护一个线程的Looper,同时通过Looper获取MessageQueue。于是其他线程只要有该Handler的引用就可以向UI线程发送Message,然后UI线程再获取该Message进行UI更新。
![](https://i-blog.csdnimg.cn/blog_migrate/cec76feff2b24a8d4234924d9c339fa7.png)
Handler默认是获取当前线程的Looper。
Handler可以发送两种对象,
- Runnable,通过post(Runnable)等发送,但本质上Runable会被封装成Message再通过sendMessage发送。
- Message,通过sendMessage(Message)发送。
功能二:消息派发
当消息通过Looper从MessageQueue取出时,进行消息派发。由于Message拥有Handler的引用,派发是通过Handler的dispatchMessage(msg)实现的。
功能三:消息处理
在前面Message中已经提到,通过Handler的handlerMessage()实现的,可以重载该方法实现自己的逻辑。
总体的思路:
![](https://i-blog.csdnimg.cn/blog_migrate/e04e07f61350a8d19939d45dcc5bad5b.png)
首先一个线程要通过Looper.prepare()创建一个Looper,然后创建一个Handler用来给其它线程向该线程发送消息,最后通过Looper.loop()进行消息循环(UI线程默认进行)。
工作线程通过Handler向UI线程发送消息,通过框架图可以知道,Handler其实是通过Looper获取UI线程的MessageQueue,然后向MessageQueue添加Message的。
添加后,UI线程调用loop()循环会不断的从MessageQueue获取Message。获取到Message后,通过Message的引用Handler调用Handler.dispatchMessage()进行消息派发。
public void dispatchMessage(Message msg) {
//优先执行msg.callback,Handler.post()就是把runnable赋值给callback
if (msg.callback != null) {
handleCallback(msg);
} else {
//mCallback就是创建Handler传进来的Callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//handler的成员函数,该函数是空的要实现自己的逻辑,需要继承Handler然后重载该方法
//这里mCallback和Handler.handlerMessage跟Java中Runnable和Thread.run()是同一个道理
handleMessage(msg);
}
}
参考源码(在线源码
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.4_r1/)