前言
在Android开发过程中,需要更新界面的UI。而更新UI是官方规定必须要主线程(ui线程)来更新的,即UI线程更新。如果在主线线程之外的线程中直接更新页面显示会报错。
延伸
学过JAVA的都知道:异常是类的内部抛出来的:查看异常源码果然
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
翻译异常:只有创建View视图的线程才能处理这个UI(这里不深入探究可见());
可调至此Blog(为什么子线程不能更新UIjavascript:void(0))
接着前言:我们知道了子线程更新UI线程会出错,拿我们不让他出错在子线程更新UI,其实本意就是 “线程间通信”,子线程获取数据(网络,本地各类参数常常是延迟操作)传送给UI线程,
方法
1:子线程引用主线程Handler,发送消息到主线程
2:View.post
3:activity.runonuithread
4:asynctask
常用的大家也许会想到这几种。我们跟进第2,3,4种源码查看
View.post
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
//AttachInfo是View内部类,表示创建View时候给予view对象与创建他的窗体的一些绑定信息,这不是我们关系的;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
//handler出来了
}
ViewRootImpl.getRunQueue().post(action);
//跟进发现本意也是Handler处理机制。
return true;
}
activity.runonuithread
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
//内部还是判断当前线程是否为UI线程 ,不是则使用Handler
mHandler.post(action);
} else {
action.run();
}
}
asynctask
更不用说了,网上一堆源码解析,本意就是封装了handler对象进行异步消息传递。
小结:由于其更新UI的本质都是Handler的引用,选择方法应当选择更加贴切需求的方法,并没有方法的优劣。各种方法只是对其的封装。
总结
由于Android是典型的GUI,但是现代GUI又必须是单线程通信,Google一下发现GUI单线程设计避免死锁和竞争,
所以我们Android设计避免多线程直接操控UI,但是UI数据的获取传递我们可以通过Android消息传递机制Handler实现。同时Handler是一套Android应用层更新UI完善并且被封装成各种类使用的优秀设计。
具体Handler解析,大家可Baidu,许多优秀的文章。