Android:子线程到底能不能更新UI?

摘要:
正如我们所知,Android只能在主线程中修改UI,因为修改UI是线程不安全的。首先看两段代码//btn1。setOnClickListener运行正常;闪回,控制台异常是:仅创建视图层次结构的原始线程ycouchitsviews//Pop-up异常btn1。setOnClickListener;源代码解释之前的博客已经解释了ViewRootImpl负责绘制视图。在requestLayout方法中,它将检查它是否是当前线程。因此,只要子线程修改UI但不更改UI布局,非主线程的异常将不会弹出=线程。currentThread()){thrownewCalledFromWrongThreadException;}}然后问题来了。假设我在onCreate时修改了UI,布局也发生了变化。为什么我没有报告错误?

问题由来

我们知道,Andoird由于修改UI是线程不安全的,只能在主线程中修改。如果多个线程修改UI肯定会花屏,于是谷歌做了限制,只能在主线程中修改UI。但是有次我在子线程中修改了UI没弹异常。

先来看两段代码

//正常运行
btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { resultTv.setText("更新TextView"); } }).start(); } });

闪退,控制台异常为:Only the original thread that created a view hierarchy can touch its views.

//弹出异常
btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { resultTv.setText("更新TextView ");//这里不一样,多了个换行符 } }).start(); } });

源码解读

之前的博客有解读ViewRootImpl是负责View的绘制,在requestLayout这个方法中会检查是否是当前线程。所以只要子线程修改UI但不改变UI布局时,不会弹出非主线程的异常。

@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.");
    }
}

那么问题来了,假设我在onCreate的时候修改UI,layout也变了,为什么没报错呢?

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    new Thread(new Runnable() {
        @Override
        public void run() {
            resultTv.setText("onCreate
");
        }
    }).start();
}

在ActivityThread中发现,ViewRootImpl是在onResume的时候被初始化的,上面那段代码sleep久一点等ViewRootImpl初始化完毕就会报错

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
         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();//ViewRootImpl在这里被初始化
            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);
            }       
    }
}

总结

  1. 子线程可以在部分情况下修改UI,如不改变布局,在onResume之前
  2. 不推荐在子线程中修改UI

免责声明:文章转载自《Android:子线程到底能不能更新UI?》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇二层网络架构,接入交换机和核心交换机提升SQLite数据插入效率低、速度慢的方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

winform知识

控件相关 1.文本框/label高度 文本框Multiline属性,设为true就可以了。改完高度后再将此属性改回来,要不然多行文本框,按回去就去下一行了。 label的改autoSize属性,设为false就可以了。 2.控件中文字居中 TextAlign属性:MiddleCenter 3.颜色属性 直接输入 #xxxx 4.如何去掉button按钮的...

Java常考面试题

Java常考面试题,整理自牛客网和程序员面试宝典,有的题不太好。 1. 什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? 答:Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自...

Delphi 中多线程同步的一些处理方法

当创建了多个线程,并且多个线程都要访问同一资源,,就有可能出现混乱,于是用Synchronize来控制,使同一时间只有一个线程使用那部分资源,Synchronize参数里面的代码就是多线程需要公共的代码!线程是进程内一个相对独立的、可调度的执行单元。一个应用可以有一个主线程,一个主线程可以有多个子线程,子线程还可以有自己的子线程,这样就构成了多线程应用了。...

Linux 线程占用CPU过高定位分析

今天朋友问我一个Linux程序CPU占用涨停了,该如何分析, CPU占用过高,模拟CPU占用过高的情况 先上一段代码: 1 #include <iostream> 2 #include <thread> 3 #include <vector> 4 5 6 int main(int argc, char *...

深入理解 Node.js 中的 Worker 线程

多年以来,Node.js 都不是实现高 CPU 密集型应用的最佳选择,这主要就是因为 JavaScript 的单线程。作为对此问题的解决方案,Node.js v10.5.0 通过 worker_threads 模块引入了实验性的 “worker 线程” 概念,并从 Node.js v12 LTS 起成为一个稳定功能。本文将解释其如何工作,以及如何使用 Wo...

Java中各种集合(字符串类)的线程安全性!!!

Java中各种集合(字符串类)的线程安全性!!! 一、概念: 线程安全:就是当多线程访问时,采用了加锁的机制;即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读取完之后,其他线程才可以使用。防止出现数据不一致或者数据被污染的情况。 线程不安全:就是不提供数据访问时的数据保护,多个线程能够同时操作某个数据,从而出现数...