开门见山:

这个误区是:子线程不能更新 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();
}

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

  1. Android通过子线程更新UI的几种方式

    一般情况下,UI的更新都少不了Handler,首先我们先了解一下Handler机制: Handler消息机制 定义 Message 线程间通信的数据单元,可通过message携带需要的数据创建对象:M ...

  2. Android子线程更新UI主线程方法之Handler

    背景: 我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的. ...

  3. Android子线程更新UI的方法总结

    版权声明:本文为博主原创文章,转载请注明出处:https://i.cnblogs.com/EditPosts.aspx?postid=6121280 消息机制,对于Android开发者来说,应该是非常 ...

  4. C#子线程更新UI控件的方法总结

    http://blog.csdn.net/jqncc/article/details/16342121 在winform C/S程序中经常会在子线程中更新控件的情况,桌面程序UI线程是主线程,当试图从 ...

  5. [Android学习笔记]子线程更新UI线程方法之Handler

    关于此笔记 不讨论: 1.不讨论Handler实现细节 2.不讨论android线程派发细节 讨论: 子线程如何简单的使用Handler更新UI 问题: android开发时,如何在子线程更新UI? ...

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

    一.一般我们都会在子线程完成一些耗时的操作. 1.Android中消息机制: 2.知识点: Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队, ...

  7. OkHttp3几个简单的例子和在子线程更新UI线程的方法

    okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿. ...

  8. Android可以子线程更新UI?

    初了解Android的时候,就知道Android是不能在子线程更新UI的,不然程序会直接抛出异常,告诉你,别给我在自线程搞事情! 但是,这个是针对普通的view做的限制,而TextureView,Su ...

  9. android子线程更新UI

    参考:https://www.cnblogs.com/joy99/p/6121280.html 子线程是不能直接更新UI的.Android实现View更新有两组方法,分别是invalidate和pos ...

随机推荐

  1. C#仪器数据文件解析-Word文件(doc、docx)

    不少仪器数据报告输出为Word格式文件,同Excel文件,Word文件doc和docx的存储格式是不同的,相应的解析Word文件的方式也类似,主要有以下方式: 1.通过MS Word应用程序的DCOM ...

  2. JAVAEE企业级应用开发浅谈第二辑:MVC和三层架构

    上海尚学堂警句:一份信心,一份努力,一份成功:十分信心,十分努力,十分成功. Step1.情景概要 Hello,小伙伴们,昨天跟大家分享了JAVA EE 企业级应用开发中大家耳熟能详的概念-三层架构, ...

  3. win10 uwp InkCanvas控件数据绑定

    本文主要说如何绑定InkCanvas,让笔画变化的时候我们可以知道. 我们本来的InkCanvas没有提供笔画绑定,所以我们自己写 using Windows.UI.Input.Inking; usi ...

  4. win10 uwp 设置启动窗口大小 获取窗口大小

    本文主要说如何设置我们窗口的启动大小,UWP启动窗口大小. 设置启动窗口 设置窗口大小 ApplicationView.PreferredLaunchViewSize = new Size(1000, ...

  5. JavaScript观察者模式

    观察者模式观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得 ...

  6. 牛顿插值法及其C++实现

    h1 { margin-bottom: 0.21cm } h1.western { font-family: "Liberation Sans", sans-serif; font ...

  7. 文本可视化[二]——《今生今世》人物关系可视化python实现

    文本可视化[二]--<今生今世>人物关系可视化python实现 在文本可视化[一]--<今生今世>词云生成与小说分析一文中,我使用了jieba分词和wordcloud实现了,文 ...

  8. Linux入门(10)——Ubuntu16.04使用pip3和pip安装numpy,scipy,matplotlib等第三方库

    安装Python3第三方库numpy,scipy,matplotlib: sudo apt install python3-pip pip3 install numpy pip3 install sc ...

  9. 01Vue数据双向绑定

    Vue作为前端MV*架构,Vue.js (读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计. Vue 的核心库只关注 ...

  10. LeetCode 599. Minimum Index Sum of Two Lists (从两个lists里找到相同的并且位置总和最靠前的)

    Suppose Andy and Doris want to choose a restaurant for dinner, and they both have a list of favorite ...