为什么能在子线程通过setText进行更新UI
为什么可以在子线程通过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相关推荐
- 为什么子线程中不能直接更新UI
点击上方"dotNET全栈开发","设为星标" 加"星标★",每天11.50,好文必达 全文约4000字,预计阅读时间8分钟 当初有同事就碰 ...
- Handler详解系列(四)——利用Handler在主线程与子线程之间互发消息,handler详解...
MainActivity如下: package cc.c;import android.app.Activity; import android.os.Bundle; import android.o ...
- Android子线程更新UI的方法总结
消息机制,对于Android开发者来说,应该是非常熟悉.对于处理有着大量交互的场景,采用消息机制,是再好不过了.有些特殊的场景,比如我们都知道,在Android开发中,子线程不能更新UI,而主线程又不 ...
- Android中Activity、Window、ViewRootImpl与子线程更新UI
三者层级关系 1.Window Window是一个抽象类,唯一的实现类是PhoneWindow Window分为三种类型应用Window.子Window.系统Window.子Window无法独立存在必 ...
- 为什么不能在子线程中更新UI
首先声明一点:子线程里面是可以更新UI的--创建一个空白的Activity,在其xml文件中放一个空白TextView,Java代码如下: @Override protected void onCre ...
- 【转】Android子线程真的不能更新UI么
Android单线程模型是这样描述的: Android UI操作并不是线程安全的,并且这些操作必须在UI线程执行 如果在其它线程访问UI线程,Android提供了以下的方式: Activity.run ...
- Android子线程真的不能更新UI么
Android单线程模型是这样描述的: Android UI操作并不是线程安全的,并且这些操作必须在UI线程执行 如果在其它线程访问UI线程,Android提供了以下的方式: Activity.run ...
- android 关于关于子线程更新UI的一些事
我们在看一些书或者博客时总是会看到一句话"android更新UI操作都是在Main主线程中,子线程中不能进行UI更新操作"那么,在子线程中真的不能进行UI的更新操作吗? //源码环 ...
- Android创建子线程和回调主线程的几种方式
一. 创建子线程//通过继承threadpublic class JNThread1 extends Thread {public JNThread1(String name){super(name) ...
最新文章
- jquery ajax统一对url编码,jQuery AJAX请求中的相对与绝对URL
- 物体抓取位姿估計算法綜述_基于深度学习的物体抓取位置估计
- 关于Exchange Server 2010中OWA页面无法打开问题处理方法
- 用计算机KADIO算方差,KADIO计算器怎样算方差
- 浏览器版本不支持页面示例 supper.html
- JavaScript深入【表达式和运算符(上集)】你能过我8关js运算符的题目吗?
- MyBatis 源码解读-settingsAsProperties()
- linux发送邮件的功能总结
- tuples_通过字典赋值
- 如何确定线程池核心数的最佳值?
- efi文件错误服务器崩溃,电脑故障分析:Winload.efi文件丢失导致蓝屏的解决方法...
- python第七章-文件和数据格式化
- 科大讯飞输入法android离线语音,讯飞输入法Android5.0.1752 离线语音更轻快的表达...
- luogu P4100 [HEOI2013]钙铁锌硒维生素
- 锐目对讲机的使用方法详解
- 如何判断一个男人将来是穷还是富?
- 湖人 PK 凯尔特人!!!
- 超详细--neo4j cypher match详细用法
- Axure RP一个专业的快速原型设计工具
- 使用原生JS封装一个Ajax