Android 中 Activity 的 onCreate 方法里面子线程为何能设置UI界面

2024-05-11 00:48

本文主要是介绍Android 中 Activity 的 onCreate 方法里面子线程为何能设置UI界面,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果之前你没有尝试过 onCreate 方法里面用子线程的 run 方法去设置 UI (比如对 Textview 进行 setText 操作),相信你看到这个标题,也会感到困惑和好奇吧。

废话不多说,先来个 Demo 。

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);iv = (ImageView) findViewById(R.id.iv);bt = (Button) findViewById(R.id.bt);Thread thread = new Thread("Thread1") {public void run() {tv.setText(System.currentTimeMillis() + "33333333");tv.append(Thread.currentThread().getName());iv.setImageResource(R.drawable.ic_launcher);};};thread.start();
}

代码很简单,就是在 onCreate 方法里面 new 了一个 Thread,然后在 run 方法里面进行 UI 操作。

运行结果如下:

没错,你要相信这正是运行结果。确实 TextView 的文本设置为当前时间的 long 型,还有子线程的名字。ImageView 也设置了默认图标

那,不是说 android 不允许子线程更新UI吗?

在这里,我们不妨再加一个 Button,在 Button 点击事件里面通过子线程来更新UI

onClick 方法代码如下:

public void onClick(View v) {// TODO 自动生成的方法存根Thread thread = new Thread("Thread1") {public void run() {tv.setText(System.currentTimeMillis() + "\n");tv.append("thread name:"+ Thread.currentThread().getName());iv.setImageResource(R.drawable.ic_launcher);};;thread.start();
}

编译后运行结果来看:

编译后程序可以启动,并且没有挂掉,界面上 TextView 和 ImageView 显示与上图一致。

但是我们点击按钮后发现程序出现 “ Unforunately,Study has stopped.” 的字样,程序挂掉了。

不难看出,onClick 里面子线程更新UI与我们的预期结果一样,但是为什么 onCreate 方法里面却没有挂掉呢。

 

在此,我选择查看一下 setText 方法,发现 setText 里面调用了 checkForRelayout();,而在 checkForRelayout 方法里面调用了invalidate()这个方法

再追踪下去,是 invalidate 方法调用了 ViewGroup.invalidateChild,最终调用 ViewRootImpl.checkThread()。

ViewRootImpl 是一个隐藏类,我们只能去看 framework 的源码,源码如下:

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

mThread是 UI 线程,这里会检查当前线程是不是 UI 线程。那么为什么 onCreate 里面没有进行这个检查呢。

 

这个问题原因出现在 Activity 的生命周期中,在 onCreate 方法中,UI处于创建过程,对用户来说界面还不可视,直到onStart方法后界面可视了,再到onResume方法后界面可以交互,。

从某种程度来讲,在onCreate方法中进行setText不能算是更新UI,只能说是配置 UI,或者是设置 UI 的属性。这个时候并不会调用 invalidate,也就是不会调用到 ViewRootImpl.checkThread() 。而在 onResume 方法后,ViewRootImpl 才被创建。这个时候去交互界面以及算是更新 UI 了,这个时候 ViewRootImpl.checkThread() 就会报错了。

不信,我们把子线程休眠200ms,代码如下:

Thread thread = new Thread("Thread1") {public void run() {try {Thread.sleep(200);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}tv.append( System.currentTimeMillis() + "\n");tv.append("thread name:" + Thread.currentThread().getName());iv.setImageResource(R.drawable.ic_launcher);};
};
thread.start();

运行结果是程序出现“Unforunately,Study has stopped

 

简单的来说,就是多线程下的问题,在 activity 的生命周期里各个方法的执行时间都有影响,而UI线程检查是由 ViewRootImpl 类调用的,而 ViewRootImpl 只有在 onRsume 方法后才会被创建。

这篇关于Android 中 Activity 的 onCreate 方法里面子线程为何能设置UI界面的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978042

相关文章

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

如何将Python彻底卸载的三种方法

《如何将Python彻底卸载的三种方法》通常我们在一些软件的使用上有碰壁,第一反应就是卸载重装,所以有小伙伴就问我Python怎么卸载才能彻底卸载干净,今天这篇文章,小编就来教大家如何彻底卸载Pyth... 目录软件卸载①方法:②方法:③方法:清理相关文件夹软件卸载①方法:首先,在安装python时,下

电脑死机无反应怎么强制重启? 一文读懂方法及注意事项

《电脑死机无反应怎么强制重启?一文读懂方法及注意事项》在日常使用电脑的过程中,我们难免会遇到电脑无法正常启动的情况,本文将详细介绍几种常见的电脑强制开机方法,并探讨在强制开机后应注意的事项,以及如何... 在日常生活和工作中,我们经常会遇到电脑突然无反应的情况,这时候强制重启就成了解决问题的“救命稻草”。那

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、

SpringMVC获取请求参数的方法

《SpringMVC获取请求参数的方法》:本文主要介绍SpringMVC获取请求参数的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下... 目录1、通过ServletAPI获取2、通过控制器方法的形参获取请求参数3、@RequestParam4、@

C#TextBox设置提示文本方式(SetHintText)

《C#TextBox设置提示文本方式(SetHintText)》:本文主要介绍C#TextBox设置提示文本方式(SetHintText),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录C#TextBox设置提示文本效果展示核心代码总结C#TextBox设置提示文本效果展示核心代

Python中的魔术方法__new__详解

《Python中的魔术方法__new__详解》:本文主要介绍Python中的魔术方法__new__的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、核心意义与机制1.1 构造过程原理1.2 与 __init__ 对比二、核心功能解析2.1 核心能力2.2