为什么我的子线程更新了 UI 没报错?借此,纠正一些Android 程序员的一个知识误区

简介: 开门见山:这个误区是:子线程不能更新 UI ,其应该分类讨论,而不是绝对的。半小时前,我的 XRecyclerView 群里面,一位群友私聊我,问题是:为什么我的子线程更新了 UI 没报错?我叫他发下代码我看,如下,十分简单的代码。

开门见山:

这个误区是:子线程不能更新 UI ,其应该分类讨论,而不是绝对的。

半小时前,我的 XRecyclerView 群里面,一位群友私聊我,问题是:

为什么我的子线程更新了 UI 没报错?

我叫他发下代码我看,如下,十分简单的代码。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    title = (TextView) findViewById(R.id.title_tips);
    doGet("http;//www.baidu.com", new Callback() {
        @Override
        public void onFailure(Request request, IOException e) {
            
        }
        @Override
        public void onResponse(Response response) throws IOException {
            title.setText(response.body().string()); // 这里在子线程更新了 text
        }
    });
}

private void doGet(String url,Callback callback) {
    OkHttpClient client = new OkHttpClient();
    
    Request.Builder builder = new Request.Builder();
    Request request = builder.url(url).get().build();

    client.newCall(request).enqueue(callback);
}

简单解析下。他用了 OkHttp 的异步 enqueue 的请求,并在成功后更新了 textView 的 text。

明确一点:

  • okhttp 的同步异步的回调都是在子线程里面的。

那么这样来说,按照我们被一直灌输的原理: 子线程不能刷新UI,上面这段代码妥妥地爆错啊。

而我要说的是:

上面的代码不一定爆错,它还会稳稳的顺利执行。

你十分怀疑了?

你可以尝试下。嫌麻烦,你可以运行下下面这段通透的子线程更新UI代码

public class TestActivity extends Activity {
    private TextView title;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        title = (TextView) findViewById(R.id.title_tips);
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        // 子线程更新UI
                        title.setText("我 tm 妥妥地执行完毕");
                    }
                }
        ).start();
    }
}

试了的都知道,真 tm 执行了没爆错。

颠覆了吗?

原因

在看到他发给我的代码,onCreate 里面的部分,一切已经明了,这也是我之前面试几年经验的人设过的坑。下面我直接讲原因,源码分析那些你们自己去看吧,你应该去看

  • 子线程不能更新 UI 的限制是 viewRootImpl.java 内部限制了

    void checkThread() {
    // 该方法是 viewRootImpl.java 内部代码
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
    }
  • 对组件 Activity 而言,viewRootImpl 的初始化在 onCreate 之后,onResume 之后。
  • 如果你的子线程更新代码在满足下面的条件下,那么它可以顺利运行:
    • 修改应用层的 viewRootImpl.java 源码,解除限制
    • 把你更新代码写在 onResume 之前,例如 onCreate 里面,且,更新之际要赶在 viewRootImpl 初始化之前。

修改验证 --- 抛出错误

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    title = (TextView) findViewById(R.id.title_tips);
    new Thread(
            new Runnable() {
                @Override
                public void run() {
                    try {
                        // 等待 onResume 执行完,让 viewRootImpl 初始化完成
                        Thread.sleep(3000); // ---------- 这里,看这里
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    title.setText("我执行不了");
                }
            }
    ).start();
}

如果您认为这篇文章还不错或者有所收获,您可以通过扫描一下下面的支付宝二维码 打赏我一杯咖啡【物质支持】,也可以点击右下角的【推荐】按钮【精神支持】,因为这两种支持都是我继续写作,分享的最大动力


img_12e3f54d4d0f70f0eb14f20548e3d781.png
目录
相关文章
|
1月前
|
JavaScript 前端开发 Java
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
IT寒冬使APP开发门槛提升,安卓程序员需转型。选项包括:深化Android开发,跟进Google新技术如Kotlin、Jetpack、Flutter及Compose;研究Android底层框架,掌握AOSP;转型Java后端开发,学习Spring Boot等框架;拓展大前端技能,掌握JavaScript、Node.js、Vue.js及特定框架如微信小程序、HarmonyOS;或转向C/C++底层开发,通过音视频项目如FFmpeg积累经验。每条路径都有相应的书籍和技术栈推荐,助你顺利过渡。
39 3
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
|
1月前
|
网络安全 图形学 Android开发
Unity与安卓丨AS报错:SSL peer shut down incorrectly
Unity与安卓丨AS报错:SSL peer shut down incorrectly
Unity与安卓丨AS报错:SSL peer shut down incorrectly
|
22天前
|
存储 搜索推荐 Java
探索安卓开发中的自定义视图:打造个性化UI组件Java中的异常处理:从基础到高级
【8月更文挑战第29天】在安卓应用的海洋中,一个独特的用户界面(UI)能让应用脱颖而出。自定义视图是实现这一目标的强大工具。本文将通过一个简单的自定义计数器视图示例,展示如何从零开始创建一个具有独特风格和功能的安卓UI组件,并讨论在此过程中涉及的设计原则、性能优化和兼容性问题。准备好让你的应用与众不同了吗?让我们开始吧!
|
22天前
|
编解码 Android开发
【Android Studio】使用UI工具绘制,ConstraintLayout 限制性布局,快速上手
本文介绍了Android Studio中使用ConstraintLayout布局的方法,通过创建布局文件、设置控件约束等步骤,快速上手UI设计,并提供了一个TV Launcher界面布局的绘制示例。
31 1
|
30天前
|
API Android开发
Android项目架构设计问题之选择和使用合适的UI库如何解决
Android项目架构设计问题之选择和使用合适的UI库如何解决
38 0
|
1月前
|
开发工具 图形学 Android开发
Unity与安卓丨unity报错:SDK Tools version 0.0 < 26.1.1
Unity与安卓丨unity报错:SDK Tools version 0.0 < 26.1.1
|
1月前
|
API Android开发 图形学
UNITY与安卓⭐三、安卓报错答疑合集
UNITY与安卓⭐三、安卓报错答疑合集
|
1月前
|
Java Android开发
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
95 1
|
1月前
|
Android开发
解決Android报错:Could not initialize class org.codehaus.groovy.reflection.ReflectionCache
解決Android报错:Could not initialize class org.codehaus.groovy.reflection.ReflectionCache
48 1
|
2月前
|
XML Android开发 UED
💥Android UI设计新风尚!掌握Material Design精髓,让你的界面颜值爆表!🎨
【7月更文挑战第28天】随着移动应用市场的发展,用户对界面设计的要求不断提高。Material Design是由Google推出的设计语言,强调真实感、统一性和创新性,通过模拟纸张和墨水的物理属性创造沉浸式体验。它注重色彩、排版、图标和布局的一致性,确保跨设备的统一视觉风格。Android Studio提供了丰富的Material Design组件库,如按钮、卡片等,易于使用且美观。
87 1