Android UI 线程更新UI也会崩溃??

这篇具有很好参考价值的文章主要介绍了Android UI 线程更新UI也会崩溃??。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

是不是有一丝的郁闷?

没关系,作为拥有多年经验的老鸟,总能立马想到解释的理由:

大家都知道在Activity#onCreate的时候,我们开个线程去执行Text#setText也不会崩溃,原因是ViewRootImpl那时候还没初始化,所以这次没崩溃也是一个原因。

对应源码解释是这样的:

Dialog源码

public void show() {

// 省略一堆代码

mWindowManager.addView(mDecor, l);

}

我们首次创建的Dialog,第一次调用show方法,内部确实会执行mWindowManager.addView,这个代码会执行到:

WindowManagerImpl

@Override

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {

applyDefaultToken(params);

mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);

}

这个mGlobal对象是WindowManagerGlobal,我们看它的addView方法:

WindowManagerGlobal

public void addView(View view, ViewGroup.LayoutParams params,

Display display, Window parentWindow) {

// 省略了一堆代码

root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);

mRoots.add(root);

mParams.add(wparams);

// do this last because it fires off messages to start doing things

try {

root.setView(view, wparams, panelParentView);

} catch (RuntimeException e) {

// BadTokenException or InvalidDisplayException, clean up.

if (index >= 0) {

removeViewLocked(index, true);

}

throw e;

}

}

果然立马有new ViewRootImpl的代码,你看ViewRootImpl没有创建,所以这和Activity那个是一个情况。

好像有那么点道理哈…

我们继续往下看。

应届小哥要继续做需求了。

一个隐藏的问题


接下来的需求很奇怪,就是当询问"鸿洋帅气吗?"的时候,如果你点击不是,那么Dialog不消失,在问题的末尾再加一个?号,如此循环,永不关闭。

这难不倒我们的小哥:

mBtnNo.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

String s = mTvTitle.getText().toString();

mTvTitle.setText(s+“?”);

}

});

运行效果:

Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui

很完美。

如果我问,你觉得这个代码有问题吗?

你往上看了几眼,就这两行代码有个鸡儿问题,可能有空指针?

当然不是。

我稍微修改一下代码:

mBtnNo.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

String s = mTvTitle.getText().toString();

mTvTitle.setText(s+“?”);

boolean uiThread = Looper.myLooper() == Looper.getMainLooper();

Toast.makeText(getContext(),"Ui thread = " + uiThread , Toast.LENGTH_LONG).show();

}

});

每次点击的时候,我弹了个Toast,输出当前线程是不是UI线程。

看下效果:

Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui

发现问题了吗?

出乎自己的意料吗?

我们在非UI线程一直在更新TextView的text。

这个时候,你不能跟我扯什么ViewRootImpl还没有创建了吧?

别急…

还有更刺激的。

更刺激的事情


我再改一下代码:

private Handler sUiHandler = new Handler(Looper.getMainLooper());

public QuestionDialog(@NonNull Context context) {

super(context);

setContentView(R.layout.dialog_question);

mBtnNo.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

sUiHandler.post(new Runnable() {

@Override

public void run() {

String s = mTvTitle.getText().toString();

mTvTitle.setText(s+“?”);

}

});

}

});

}

我搞了个UI线程的handler,然后post一下Runnable,确保我们的TextView#setText在UI线程执行,严谨而又优雅。

再停一下,以各位多年经验,这次会崩溃吗?

按照我写博客的套路,这次肯定是演示崩溃呀,不然博客怎么往下写。

好像是这个道理…

我们跑一下效果:

[图片上传中…(image-bfd5c6-1588405433234-1)]

点击了几下,没崩…

// 配图:小朋友,你是不是有很多问号。

作为拥有多年经验的老鸟,总能立马想到解释的理由:

UI线程更新当然不会崩溃呀(言语中有一丝不自信)。

是吗?

我们多点击几次:

Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui

崩溃了…

但是刚才在没有添加UiHandler.post之前可没有崩溃哟。

这个结果,我都得把代码露出来了,怕你们说我演你们…

好了,再停一停。

我又要问大家一个问题了,这次你猜是什么崩溃?

是不是求我别搞你们了,直接揭秘吧。

com.example.testviewrootimpl E/AndroidRuntime: FATAL EXCEPTION: main

Process: com.example.testviewrootimpl, PID: 18323

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8188)

at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1421)

at android.view.View.requestLayout(View.java:24434)

at android.view.View.requestLayout(View.java:24434)

at android.view.View.requestLayout(View.java:24434)

at android.view.View.requestLayout(View.java:24434)

at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:380)

at android.view.View.requestLayout(View.java:24434)

at android.widget.TextView.checkForRelayout(TextView.java:9667)

at android.widget.TextView.setText(TextView.java:6261)

at android.widget.TextView.setText(TextView.java:6089)

at android.widget.TextView.setText(TextView.java:6041)

at com.example.testviewrootimpl.QuestionDialog$1$1.run(QuestionDialog.java:38)

at android.os.Handler.handleCallback(Handler.java:883)

at android.os.Handler.dispatchMessage(Handler.java:100)

at android.os.Looper.loop(Looper.java:214)

at android.app.ActivityThread.main(ActivityThread.java:7319)

at java.lang.reflect.Method.invoke(Native Method)

at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:934)

那个熟悉的身影回来了:

Only the original thread that created a view hierarchy can touch its views.

但是!

但是!

这次可是在切换到UI线程抛出来的。

对应我开头的灵魂拷问:

UI线程更新UI就不会出现上面的错误了吗?

是不是在一股懵逼又刺激的感觉中无法自拔…

还有更刺激的事情…嗯,篇幅问题,本篇我们就到这了,更刺激的事情我们下次再写。

别怕,没完,我总得告诉你们为什么吧。

小做揭秘


其实这一切的根源都在于我们长久的一个错误的概念。

就是UI线程才能更新UI,这是不对的,为什么这么说呢?

Only the original thread that created a view hierarchy can touch its views.

这个异常是在ViewRootImpl里面抛出的对吧,我们再次来审视一下这段代码:

void checkThread() {

if (mThread != Thread.currentThread()) {

throw new CalledFromWrongThreadException(

“Only the original thread that created a view hierarchy can touch its views.”);

}

}

其实就几行代码。

我们仔细看一下,他这个错误信息并不是:

Only the UI Thread … 而是 Only the original thread

对吧,如果真的想强制为Only the Ui Thread,上面的if语句应该写成:

if(UI Thread== Thread.currentThread()){}

而不是mThread。

根本原因说完了。

我再带大家看下源码解析:

这个mThread是什么?

是ViewRootImpl的成员变量,我们重点应该关注它什么时候赋值的:

public ViewRootImpl(Context context, Display display) {

mContext = context;

mThread = Thread.currentThread();

}

在ViewRootImpl构造的时候赋值的,赋值的就是当前的Thread对象。

也就是说,你ViewRootImpl在哪个线程创建的,你后续的UI更新就需要在哪个线程执行,跟是不是UI线程毫无关系。

对应到上面的例子,我们中间也有段贴源码的地方。

恰好说明了:

Dialog的ViewRootImpl,其实是在执行show()方法的时候创建的,而我们的Dialog的show放在子线程里面,所以导致后续View更新,执行到ViewRootImpl#checkThread的时候,都在子线程才可以。

这就说明了,为什么我们刚才切到UI线程去执行TextView#setText为啥崩了。

这里有个思考题,注意我们上面演示的时候,切到UI线程执行setText没有立马崩溃,而是执行了好几次之后才崩溃的,为什么呢?自己想。

大家可能还有个一问题:

ViewRootImpl怎么和View关联起来的

其实我们看报错堆栈很好找到相关代码:

com.example.testviewrootimpl E/AndroidRuntime: FATAL EXCEPTION: main

Process: com.example.testviewrootimpl, PID: 18323

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8188)

at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1421)

at android.view.View.requestLayout(View.java:24434)

报错的堆栈都是由View.requestLayout触发到ViewRootImpl的。

我们直接看这个方法:

public void requestLayout() {

if (mParent != null && !mParent.isLayoutRequested()) {

mParent.requestLayout();

}

注意里面这个mParent变量,它的类型是ViewParent接口。

见名知意。

我要问你一个View的mParent是什么,你肯定会回答是它的父View,也就是个ViewGroup。

对,没错。

public abstract class ViewGroup extends View implements ViewParent{}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui
Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui
Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui
Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui

七大模块学习资料:如NDK模块开发、Android框架体系架构…

Android UI 线程更新UI也会崩溃??,Android程序员面试,android,ui

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!文章来源地址https://www.toymoban.com/news/detail-842892.html

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。如有需要获取完整的资料文档的朋友点击我的【GitHub】免费获取。

实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-ChnPFSr9-1710762804344)]

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

[外链图片转存中…(img-OlwSx2AG-1710762804345)]

七大模块学习资料:如NDK模块开发、Android框架体系架构…

[外链图片转存中…(img-ukdG2MtC-1710762804345)]

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。如有需要获取完整的资料文档的朋友点击我的【GitHub】免费获取。

到了这里,关于Android UI 线程更新UI也会崩溃??的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android相机开发实战,Android程序员必看

    由于需求不同,所以选择的方案固然也不同,至于第二种调用系统相机,这里就不过多讲解了,使用Intent对象设置一个Action动作即可,跳转时使用startActivityForResult,然后在onActivityResult处理相关数据便可,关键代码: intent.setAction(“android.media.action.STILL_IMAGE_CAMERA”); 至于使用

    2024年04月15日
    浏览(46)
  • 【学习笔记】黑马程序员Java课程学习笔记(更新至第12章---集合)

    Java语言是美国Sun公司(Stanford University Network)在1995年推出的计算机语言, 2009年Oracle甲骨文公司收购Sun公司。Java之父:詹姆斯·高斯林(James Gosling)。 Java可以在任意操作系统上运行,Windows、Mac、Linux。我们只需要在运行Java应用程序的操作系统上,安装一个与操作系统对应

    2024年02月07日
    浏览(47)
  • 区块链钱包开发(Android篇),Android程序员必会

    布隆过滤器(Bloom Filter):过滤掉那些不包含有目标地址的交易信息,这一步能避免掉大量不相关的数据下载。 创建区块链 //创建区块链文件 File blockChainFile = new File(getDir(“blockstore”, Context.MODE_PRIVATE), “blockchain”); //创建SPVBlockStore,管理区块数据 blockStore = new SPVBlockStore(Co

    2024年04月09日
    浏览(81)
  • 【正在更新】【最新!黑马程序员Python自学课程笔记】课上笔记+案例源码+作业源码

    1.1字面量 1.2注释 1.3变量 debug工具的使用 1.对着某行代码 打断点 2.下方一步步 步进 1.4数据类型 1.5数据类型转换 错误示例 1.6标识符 变量的命名规范: 1.见名知意,简洁; 2.(多个单词)用下划线命名法 3.英文字母全小写 1.7运算符 1.8字符串的三种定义方式 1.9字符串的拼接

    2024年01月21日
    浏览(53)
  • Android OpenCV(四十三),Android程序员面试必备的知识点

    标志位 值 含义 GC_INIT_WITH_RECT 0 使用提供的矩形初始化状态和掩码。 之后根据算法进行迭代更新 GC_INIT_WITH_MASK 1 使用提供的掩码初始化状态。 可以组合使用GC_INIT_WITH_RECT和GC_INIT_WITH_MASK。 然后,使用GC_BGD自动初始化ROI之外的所有像素。 GC_EVAL 2 表示算法应该恢复 GC_EVAL_FREEZE_

    2024年04月09日
    浏览(51)
  • Android程序员向音视频进阶,有前景吗

    随着移动互联网的普及和发展,Android开发成为了很多人的就业选择,希望在这个行业能获得自己的一席之地。然而,随着时间的推移,越来越多的人进入到了Android开发行业,就导致目前Android开发的工作越来越难找,内卷非常严重,最近听说音视频开发是Android未来的一个出口

    2023年04月24日
    浏览(55)
  • ChatGPT在连续追问下对多线程和双重检查锁模式的理解--已经超越中级程序员

    一、问: 二、ChatGPT答:  在多线程情况下,可能会出现GZHttpClientResultModel model为null的情况,因为CACHE_RESULT_MODEL是一个ConcurrentHashMap对象,虽然它本身是线程安全的,但是它内部的操作不是完全线程安全的。 比如在cacheResultMode方法中,如果两个线程同时接近CACHE_RESULT_MODEL.con

    2023年04月27日
    浏览(40)
  • 身为一个后端程序员如何快速制作后端管理系统的UI

    我的专业领域在后端开发上,前端我仅仅是熟悉,但是要从头开发一个前端UI界面有点难为人了。那么身为一个后端程序员我们怎么来开发后端管理系统UI界面呢? 市面上有很多后端管理系统的UI模版,但我推荐的layui + lauyimini,虽然技术偏老,也没咋维护了,但是上手简单呀

    2024年02月11日
    浏览(48)
  • Flutter Navigator 2(1),一个Android程序员的面试心得

    onPressed: () { Navigator.pushNamed( context, ‘/details/1’, ); }, ), ), ); } } class DetailScreen extends StatelessWidget { String id; DetailScreen({ this.id, }); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(‘Viewing details f

    2024年04月12日
    浏览(42)
  • mint-ui使用,面试一路绿灯Offer拿到手软,最新大厂程序员进阶宝典

    mint-ui 的使用 mint-ui官网 安装 npm install mint-ui -S 引入项目 全局引入(简单粗暴,一次引入所有组件) main.js // 引入全部组件 import Vue from ‘vue’; import Mint from ‘mint-ui’; import ‘mint-ui/lib/style.css’; // 有可能会报错, 找node_modules --》 mint-ui ?css Vue.use(Mint); 弹框 Toast组件 import {

    2024年04月08日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包