Android在子线程更新UI的4种方法
搞Android开发也有一段时间了,期间看过很多的博客、源码,但是到现在存在自己记忆中的知识点却廖廖无几,反思了原因:每次都是遇到问题解决问题,没有养成记录总结的习惯,以至于现在感觉自己和一个初学者差不多,所以希望以后自己都能把看到的好文章都记录下,并且用自己的理解重新整理到博客。这是个好的开始,希望能坚持下去。
参考博客:http://blog.csdn.net/biezhihua/article/details/44160657
http://www.cnblogs.com/xirihanlin/archive/2011/04/11/2012746.html
Android系统是不允许在子线程更新UI界面的,但是很多时候我们在子线程处理了一些任务,完成后需要将结果发布到UI线程,这时候怎么办呢?这时候就需要用到线程间的异步消息处理技术,由子线程将需要执行的操作包装成消息对象加入到UI线程的消息队列中。然后UI线程取出消息并执行。下面总结了四种方式实现UI操作的异步处理:
方式一:Handler和Message
① 实例化一个Handler并重写handlerMessage()方法
private Handler handler = newHandler() {
public voidhandleMessage(android.os.Message msg) {
// 处理消息
}; };
② 在子线程中获取或创建消息,并使用handler对象发送。
Message msg = Message.obtain();
msg.obj = result;
handler.sendMessage(msg);
方式二:在子线程中直接调用Activity.runOnUiThread(Runnable action)方法
runOnUiThread(new Runnable() {
@Override
public void run() {
// 更新UI的操作
}
});
方式三:在子线程中调用View的post()方法
myView.post(new Runnable() {
@Override
public void run() {
// 更新UI
myView.setText(“更新UI”);
}});
方式四:Handler的post()方法
① 创建一个Handler成员变量
private Handler handler = new Handler();
② 在子线程中调动post()方法
handler.post(new Runnable() {
@Override
public void run() {
// 更新UI
myView.setText(“更新UI”);
}});
其实以上介绍的方法实现的原理都是差不多的,都是基于第一种Handler+Message实现的,具体可参考源码实现。下面总结下Handler+Message的实现机制,下面是一张关系图:
先解释下图中出现的关键字的含义:
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。当我们创建一个Handler时,它会自动绑定到创建它的当前线程。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。在Android的UI主线程中都会自动创建有一个Looper对象,但是并不是每个线程都会有Looper对象,在其他线程我们需要调用Looper.prepare()方法来获得Looper对象。
所以一个异步处理消息的整个过程就是,子线程通过与主线程绑定的Handler将需要执行的UI操作发送到主线程的消息队列中,然后主线程将其取出执行。