开门见山:

这个误区是:子线程不能更新 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. 3.ElasticSearch的倒排索引

    一. 正向索引 常规的索引建立方式 文档---> 关键词的映射过程(正向索引) 比如: 我有很多个文章,如果想查询其中几个文章是否含有刘耀这个关键词,那么我就需要打开所以文章,找到里面含义刘耀的 ...

  2. HTML之头部标签

    <header> head 元素元素包含了所有的头部标签元素 可以添加在头部区域的元素标签为: title,style,meta,link,script,noscript,base < ...

  3. 开发人员的福音:微软、谷歌、Mozilla将他们所有的web API文档放在同一个地方

    Tips 原文作者:Liam Tung  原文地址:Developers rejoice: Microsoft, Google, Mozilla are putting all their web A ...

  4. apache+php+mysql运行环境

    建议Apache2.4+php5.6+mysql5.5+phpmyadmin4.4.4 参考: http://jingyan.baidu.com/article/fcb5aff797ec41edaa4 ...

  5. Integrates Git with Sublime 3 to pull or push to Github by using Sublime plugin Git

    1. Git must be installed, Sublime plugin "Git" only connects Sublime with Git. Download UR ...

  6. 浅试 Webview 一app 加载 H5小游戏

    整体架构: InventionActivity:实现UI的实例化,基本的按钮Activity之间跳转 GameActivity:实现UI的实例化,Webview的基本使用 MyProgressDial ...

  7. 用gdb调试python多线程代码-记一次死锁的发现

    | 版权:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.如有问题,可以邮件:wangxu198709@gmail.com 前言 相信很多人都有 ...

  8. python函数前篇

    函数:函数是指将一组语句的集合通过一个函数名封装起来,要想执行这个函数,只需调用其函数名即可 函数特性: 减少重复代码 使程序变得可扩展 使程序变得易维护 什么是函数? 函数就是具备某一特定功能的工具 ...

  9. require.js实现js模块化编程(二):RequireJS Optimizer

    require.js实现js模块化编程(二):RequireJS Optimizer 这一节,我们主要学习一下require.js所提供的一个优化工具r.js的用法. 1.认识RequireJS Op ...

  10. C++ 标准库之iomanip

    C++ 标准库之iomanip istream & istream::get(char *, int, char = '\n');istream & istream::getline( ...