为什么可以在子线程通过setText进行更新UI

void checkThread() {if (mThread != Thread.currentThread()) {throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");}}

一般情况下在子线程更新UI是会报错的,因为在ViewRootImpl中会通过checkThread进行检查,在ViewRootImpl还没创建的时候是不会检查的,但这里主要是对已经创建ViewRootImpl还可以更新UI进行分析。

我们直接看下通过子线程setText不会报错的代码和运行结果。

public class MainActivity extends AppCompatActivity implements View.OnClickListener  {TextView text;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text= findViewById(R.id.text); }@Overridepublic void onClick(View v) {new Thread((Runnable)()->{text.setText("改变后");}).start();}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"><TextViewandroid:id="@+id/text"android:layout_width="100dp"android:layout_height="100dp"android:background="@color/colorAccent"android:text="改变前"/><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Button"android:onClick="onClick"/></LinearLayout>


我们能看到在点击后是能顺利进行更新UI的。关键点就在于 android:layout_width=“100dp” android:layout_height=“100dp”
我这里把视图大小进行了固定。出错肯定是触发了checkThread,但是只要不触发就可以顺利更新UI,而setText不是在任何情况下都会触发checkThread的。

在setText方法中会调用 checkForRelayout,而这个方法就展现了不会触发checkThread的原因。checkThread是在requestLayout中才会进行的,所有这里只要不调用requestLayout就不会进行checkThread。

通过下面的源代码就会发现不是所有情况都会调用requestLayout。在两个return那里都是没用调用requestLayout,所以我们可以知道只要View的大小不是wrap_content,而是match_parent或者是固定不变的dp,就都不会触发requestLayout,自然就可以在子线程更新了。

private void checkForRelayout() {// If we have a fixed width, we can just swap in a new text layout// if the text height stays the same or if the view height is fixed.if ((mLayoutParams.width != LayoutParams.WRAP_CONTENT|| (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))&& (mHint == null || mHintLayout != null)&& (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {// Static width, so try making a new text layout.int oldht = mLayout.getHeight();int want = mLayout.getWidth();int hintWant = mHintLayout == null ? 0 : mHintLayout.getWidth();/** No need to bring the text into view, since the size is not* changing (unless we do the requestLayout(), in which case it* will happen at measure).*/makeNewLayout(want, hintWant, UNKNOWN_BORING, UNKNOWN_BORING,mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(),false);if (mEllipsize != TextUtils.TruncateAt.MARQUEE) {// In a fixed-height view, so use our new text layout.if (mLayoutParams.height != LayoutParams.WRAP_CONTENT&& mLayoutParams.height != LayoutParams.MATCH_PARENT) {autoSizeText();invalidate();return;}// Dynamic height, but height has stayed the same,// so use our new text layout.if (mLayout.getHeight() == oldht&& (mHintLayout == null || mHintLayout.getHeight() == oldht)) {autoSizeText();invalidate();return;}}// We lose: the height has changed and we have a dynamic height.// Request a new view layout using our new text layout.requestLayout();invalidate();} else {// Dynamic width, so we have no choice but to request a new// view layout with a new text layout.nullLayouts();requestLayout();invalidate();}}

总结:
1.调用requestLayout是因为内容需要新的视图布局,当不需要的情况下就不会调用。
2.在子线程对UI更新对是通过checkThread来防止在子线程更新。
3.当View更新时调用requestLayout才会触发CheckThred,只要不调用requestLayout就意味着可以在子线程进行更新。

为什么能在子线程通过setText进行更新UI相关推荐

  1. 为什么子线程中不能直接更新UI

    点击上方"dotNET全栈开发","设为星标" 加"星标★",每天11.50,好文必达 全文约4000字,预计阅读时间8分钟 当初有同事就碰 ...

  2. Handler详解系列(四)——利用Handler在主线程与子线程之间互发消息,handler详解...

    MainActivity如下: package cc.c;import android.app.Activity; import android.os.Bundle; import android.o ...

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

    消息机制,对于Android开发者来说,应该是非常熟悉.对于处理有着大量交互的场景,采用消息机制,是再好不过了.有些特殊的场景,比如我们都知道,在Android开发中,子线程不能更新UI,而主线程又不 ...

  4. Android中Activity、Window、ViewRootImpl与子线程更新UI

    三者层级关系 1.Window Window是一个抽象类,唯一的实现类是PhoneWindow Window分为三种类型应用Window.子Window.系统Window.子Window无法独立存在必 ...

  5. 为什么不能在子线程中更新UI

    首先声明一点:子线程里面是可以更新UI的--创建一个空白的Activity,在其xml文件中放一个空白TextView,Java代码如下: @Override protected void onCre ...

  6. 【转】Android子线程真的不能更新UI么

    Android单线程模型是这样描述的: Android UI操作并不是线程安全的,并且这些操作必须在UI线程执行 如果在其它线程访问UI线程,Android提供了以下的方式: Activity.run ...

  7. Android子线程真的不能更新UI么

    Android单线程模型是这样描述的: Android UI操作并不是线程安全的,并且这些操作必须在UI线程执行 如果在其它线程访问UI线程,Android提供了以下的方式: Activity.run ...

  8. android 关于关于子线程更新UI的一些事

    我们在看一些书或者博客时总是会看到一句话"android更新UI操作都是在Main主线程中,子线程中不能进行UI更新操作"那么,在子线程中真的不能进行UI的更新操作吗? //源码环 ...

  9. Android创建子线程和回调主线程的几种方式

    一. 创建子线程//通过继承threadpublic class JNThread1 extends Thread {public JNThread1(String name){super(name) ...

最新文章

  1. jquery ajax统一对url编码,jQuery AJAX请求中的相对与绝对URL
  2. 物体抓取位姿估計算法綜述_基于深度学习的物体抓取位置估计
  3. 关于Exchange Server 2010中OWA页面无法打开问题处理方法
  4. 用计算机KADIO算方差,KADIO计算器怎样算方差
  5. 浏览器版本不支持页面示例 supper.html
  6. JavaScript深入【表达式和运算符(上集)】你能过我8关js运算符的题目吗?
  7. MyBatis 源码解读-settingsAsProperties()
  8. linux发送邮件的功能总结
  9. tuples_通过字典赋值
  10. 如何确定线程池核心数的最佳值?
  11. efi文件错误服务器崩溃,电脑故障分析:Winload.efi文件丢失导致蓝屏的解决方法...
  12. python第七章-文件和数据格式化
  13. 科大讯飞输入法android离线语音,讯飞输入法Android5.0.1752 离线语音更轻快的表达...
  14. luogu P4100 [HEOI2013]钙铁锌硒维生素
  15. 锐目对讲机的使用方法详解
  16. 如何判断一个男人将来是穷还是富?
  17. 湖人 PK 凯尔特人!!!
  18. 超详细--neo4j cypher match详细用法
  19. Axure RP一个专业的快速原型设计工具
  20. 使用原生JS封装一个Ajax

热门文章

  1. js 手写 原型链 继承
  2. 第四届宁波赛初赛赛题 wp
  3. 树莓派python安装库的位置
  4. 源壁纸微信小程序源码,小米壁纸自动更新采集
  5. 花呗额度快充显示服务器调整,花呗有新变化,快充额度被关闭,还能快速提额吗?...
  6. wps表格中加下拉三角形(在EXCEL中设置表中的下拉三角形)
  7. 2022R1快开门式压力容器操作试题及答案
  8. Python扑克牌21点小游戏
  9. openfalcon 组件监控_我对开源版本openfalcon的变更
  10. 从社群现状出发怎么做运营