大家都知道android是不允许在子线程中更新UI操作的,所有更新操作都应该在主线程中完成,因而有了异步消息处理机制,具体源码分析见android-----Handler消息处理机制那么除了通过sendMessage以及handleMessage还有哪些方法可以在子线程中书写更新UI操作的代码呢?
(1)通过Handler的post方法;
(2)通过View的post方法;
(3)通过Activity的runOnUiThread方法;
(1)通过Handler的post方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
可以看到post方法实际上调用的是sendMessageDelayed方法,这个方法的第一个参数是一个Message对象,通过getPostMessage方法将当前的Runnable对象封装成一个Message对象:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
也就是会把Mesasge的callback属性设置为Runnable对象,而sendMessageDelayed会调用sendMessageAtTime方法,该方法会调用enqueueMessage方法将当前对象加入到消息队列中去
当我们的消息队列采用死循环进行消息处理的时候,首先会调用dispatchMessage方法,这个方法的源码:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
首先会查看当前Message的callback属性是否为null,因为刚刚在post的时候已经设置该callback属性,所以不为null,那么会执行handleCallback方法,该方法的源码:
private static void handleCallback(Message message) {
message.callback.run();
}
很简单,就是直接执行当前线程而已啦!
我们来一个实例:
该实例通过点击界面上的按钮,为ImageView设置一张显示图来模拟更新界面:
public class MainActivity extends Activity {
public Button mButton = null;
public ImageView mImageView = null;
public Handler mHandler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button)findViewById(R.id.button);
mImageView = (ImageView)findViewById(R.id.imageView);
mHandler = new Handler();
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
new Thread(){
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
//更新UI的具体操作(我们以加载一张图片到ImageView为例进行)
mImageView.setBackgroundResource(R.drawable.ic_launcher);
}
});
};
}.start();
}
});
}
}
(2)通过View的post方法
首先先去View中查看此post方法:
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
}
很明显第4行我们发现其实实际上View中的post方法本质上还是调用的Handler的post方法
(3)通过Activity的runOnUiThread方法
再来看看Activity的runOnUiThread方法:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
那么很简单的一点,第2行首先判断当前线程是不是可以更新UI操作的主线程,如果不是的话,第3行同样也是调用的Handler的post方法,如果是主线程的话,则直接执行当前线程就可以啦!