异步更新UI的四种方法
- Handler.sendMessage(Message)
- Handler.post(Runnable)
- Activity.runOnUiThread(Runnable)
- View.post(Runnable)
源码简析
第一种:Handler.sendMessage() (推荐)
在主线程定义
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
mTv1.setText("这是Handler发送的Message");
}
};
发送消息
private void btn2Click() {
new Thread(new Runnable() {
@Override
public void run() {
Message message = mHandler.obtainMessage();
mHandler.sendMessage(message);
}
}).start();
}
处理消息
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
mTv1.setText("这是Handler发送的Message");
}
};
Handler机制在Android中使用比较频繁,像Activity的生命周期都是通过Handler机制进行回调的.
详细源码可参看:Hanlder、Looper、MessageQueue源码解析
第二种:Handler.post() (推荐)
这是Handler.sendMessage()发送消息的另一种写法,更简洁
private void btn2Click() {
new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(new Runnable() {
@Override
public void run() {
mBtn2.setText("这是Handler的post");
}
});
}
}).start();
}
这种方法是把Runnable任务封装到Message中,通过Handler再把消息发送到消息队列,通过Looper对消息队列进行循环,再把消息发送给Handler进行UI的更新.
详细源码可参看:Hanlder、Looper、MessageQueue源码解析
第三种:Activity.runOnUiThread() (推荐)
如果在Activity中,可以使用更简洁的runOnUiThread更新代码,不用创建Handler对象
private void btn2Click() {
new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mBtn1.setText("这是runnUiThread");
}
});
}
}).start();
}
Activity.runOnUiThread源码
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
runOnUiThread()方法是属于Activity的,所以只能在Activity中调用
首先判断是否在UI线程
- 如果不在UI线程,则和第二种一样,调用Handler.post方法更新UI
- 如果在UI线程,则直接调用Runnable任务的run方法更新UI
第四种:View.post() (强力不推荐)
如果有子view或自定义view,处理逻辑后可以直接用view.post()方法
private void btn2Click() {
new Thread(new Runnable() {
@Override
public void run() {
mBtn2.post(new Runnable() {
@Override
public void run() {
mTv1.setText("这是View的post");
}
});
}
}).start();
}
View.post源码
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
getRunQueue().post(action);
return true;
}
当AttachInfo对象不为空时,也是调用Handler.post()方法更新UI
不推荐原因:
- 在api24(不包括)以下,可通过View.post()方法更新UI
- 在Android 7.0 api24,Android 8.0 api25的手机上如果通过new创建的View,如果没有将它通过addView()加入到ViewGroup布局中,那通过View.post()将无法更新UI
总结
通过源码得知,四种方法其实归根结底都是在使用Handler机制更新UI。