子线程是否可以更新UI-Android

Posted hequnwang10

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了子线程是否可以更新UI-Android相关的知识,希望对你有一定的参考价值。

android 中子线程在满足一定的条件下可以更新 UI。
首先说一下抛出异常at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7905)

@Override
public void requestLayout() 
        if (!mHandlingLayoutInLayoutRequest) 
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        


void checkThread() 
    if (mThread != Thread.currentThread()) 
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    

当访问 UI 时,ViewRootImpl 会调用 checkThread 方法去检查当前访问 UI 的线程是否为创建 UI 的那个线程,如果不是。则会抛出异常。

scheduleTraversals()里是对View进行绘制操作,而在绘制之前都会检查当前线程是否为主线程mThread,如果不是主线程,就抛出异常;这样做法就限制了开发者在子线程中更新UI的操作;
但是为什么最开始的在onCreate()里子线程对UI的操作没有报错呢,可以设想一下是因为ViewRootImp此时还没有创建,还未进行当前线程的判断;

ViewRootImp在何时创建
从Activity启动过程中寻找源码,通过分析可以查看ActivityThread.java源码,并找到handleResumeActivity方法:

final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward, boolean reallyResume) 
        ···
        // TODO Push resumeArgs into the activity for consideration
        ActivityClientRecord r = performResumeActivity(token, clearHide);
        if (r.window == null && !a.mFinished && willBeVisible) 
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) 
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                

             else if (!willBeVisible) 
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            
        ···

内部调用了performResumeActivity方法。

从源码分析可得知,ViewRootImpl对象是在onResume方法回调之后才创建,那么就说明了为什么在生命周期的onCreate方法里,甚至是onResume方法里都可以实现子线程更新UI,因为此时还没有创建ViewRootImpl对象,并不会进行是否为主线程的判断;因此在onCreate()、onStart()、onResume()中可以做子线程更新UI

下面方法可以用来在子线程更新UI

  1. new Handler(getMainLooper).post(new Runnable()
  2. runOnUiThread(new Runable)
  3. 通过handler发送message来更新Ui

其实runOnUiThread内部就是调用new Handler(getMainLooper).post,而new Handler(getMainLooper).post内部调用的是sendMessageDelayed,所以更新Ui的原理就是通过handler发送message

开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系

以上是关于子线程是否可以更新UI-Android的主要内容,如果未能解决你的问题,请参考以下文章

在多线程中,子线程更新主线程ui都有哪些方法及注意点

多线程学习之--真的不能在子线程里更新UI吗?

子线程更新UI界面的2种方法

为啥loop之后就可以子线程更新ui

MFC中如何实现Tab控件里子对话框里的控件跟着对主话框伸缩而改变位置

Android 异步更新UI-线程池-Future-Handler实例分析