我是靠谱客的博主 纯情身影,这篇文章主要介绍安卓子线程更新UI不闪退的问题,现在分享给大家,希望可以做个参考。

子线程不能更新UI已经是一个常识了,如果两个线程同时更新UI,可能对同一个控件操作造成混乱,而更新UI涉及到整棵View树的遍历,加锁又影响效率,索性在ViewRootIlmpl类中设置一个checkThread()方法,检测当前线程和创建View的线程是否是同一个,如果不是直接Throw Exception,这就是不能在子线程更新UI的原理。但是实测发现在某些情况下可以在子线程中更新UI。

一、在onCreate中更新UI

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.text);
        new Thread(new Runnable() {
            @Override
            public void run() {
                textView.setText("apple");
            }
        }).start();
    }

这个例子网上举的很多了,因为onCreate回调可能发生在ViewRootImpl创建之前,在textView.setText中的mLayout为null,所以此时是不会深入到ViewRootImpl里执行的,这个时候textView甚至没有显示出来,所以不需要调用onDraw重绘,只是单纯改变一个变量而已。

if (mLayout != null) {
    checkForRelayout();
}

二、不改变大小更新UI

实测在我的小米手机上不改变当前控件大小只改变内容,可以正常更新不会闪退。这个情况网上目前只看到一篇文章提到,但是没有找到正确的原因。根据网上的传统分析,不改变大小时,checkForReLayout只会调用invalidate(改变大小会同时调用requestLayout和invalidate),invalidate的调用过程百度“invalidate源码”可以看到很多分析,简单说就是不断调用父view的invalidateChildParent,直到到达ViewRootImpl的invalidateChildParent,ViewRootImpl的invalidateChildParent,会执行checkThread()检测线程,从而闪退。然而在我的小米手机上并不会调用父view的invalidateChildParent方法。关键代码和调试截图如下:

final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null && attachInfo.mHardwareAccelerated) {
            // HW accelerated fast path
            onDescendantInvalidated(child, child);
            return;
        }

在检测到硬件加速位mHardwareAccelerated为true后会不断调用父view的onDescendantInvalidated,从而避开了网上源码分析中各级view对Dirty区域的反复检测处理(我也没理解为什么要反复检测处理),直接到达ViewRootImpl的onDescendantInvalidated()方法,而该方法并没有检查线程这一步,所以在子线程中可以正常更新UI。希望这篇文章可以提示一点同样遇到此问题的人,但是还不知道这个mHardwareAccelerated从何而来,硬件加速指的又是什么。

最后

以上就是纯情身影最近收集整理的关于安卓子线程更新UI不闪退的问题的全部内容,更多相关安卓子线程更新UI不闪退内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(116)

评论列表共有 0 条评论

立即
投稿
返回
顶部