前言

在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,许多优秀的文章。