Android UI线程

你问这个问题,我想了很久。
你有点理论化,但没关系。
我们就以朋友的身份聊聊,说说我掉进陷阱的那次吧。

我记得当时还在做一个小程序,有哥们告诉我,UI线程就是更新UI的线程吧?那时他看上去很严肃。
我是对的。
UI 是在单线程中更新的吗?他说是的。
当时我没有多想,我觉得这是对的。

后来我创建了一个活动并想创建一个按钮。
单击该按钮可打开一个对话框。
我在onCreate中做了,没有报错,很好。
但后来我改变了位置并在子线程中执行了操作。
我想打开一个弹出窗口,但是它报了一堆错误,说我不是原始线程,无法操作视图。
我当时就一头雾水,心想:我不是让框架出现在主线程里吗?为什么不呢?
查看源码后发现ViewRootImpl构建时并不在主线程上。
我只是想,这是哪个线程?经过一番查找,发现是ActivityThread的线程。
这时我才意识到ViewRootImpl创建的线程是UI线程而不是主线程。
那么如果我在子线程中进行操作,这当然是不行的。

后来就习惯了在子线程中完成流程,然后发布到UI线程中。
例如,如果我创建一个处理程序或直接使用 View.post ,那就没问题了。
我记得有一次我忘了发帖,程序就直接崩溃​​了。
我以为代码有问题。
检查后发现忘记直接发布操作UI线程了。
当然没用。

所以UI线程不一定是主线程,而是创建ViewRootImpl的线程。
因此,在子线程中操作UI时,一定要记得post回来,否则会报错。
这让我陷入了很多陷阱,所以现在我每次都非常小心,生怕再次陷入另一个陷阱。

你问的这些问题其实是我在开发过程中遇到的事情,但是当时我可能没有考虑得那么清楚。
你问完之后,我会帮你整理思路。
希望对您有所帮助。
如果您还有任何疑问,请随时询问我。
虽然我可能无法回答您的问题,但我会尽力帮助您找到解决方案。

android中怎么区分UI主线程和子线程

说白了,Android程序运行时默认只有一个进程,但主线程(UI线程)应该保持活动状态,其他耗时的任务应该转移到子线程中,利用Handler+Looper机制来执行。
这个问题比较复杂,如何安全地同步多个线程,但主要是两个层面:消息队列和消息处理。
我们先来说说最重要的事情。
主线程(UI Thread)仅在程序启动时创建。
所有的UI工作都应该由它来完成。
去年,百万用户的APP。
只要主线程卡顿时间超过5 毫秒,用户就会明显感觉到卡顿。
还有一点是,对于访问网络之类的任务,去年的测试发现,在主线程中发出3 000级的数据请求会导致ANR。
然而,使用子线程和处理程序后,交付结果的响应时间直接降至 5 0 毫秒以下。
还有另一个重要的细节。
控制器本身是在主线程中创建的。
消息队列通过Looper进行绑定。
线程将耗时的任务转换为消息并将其放入队列中。
当主线程繁忙时,它会一一运行它们。
去年重构时,我们意识到不主动删除消息可能会导致内存泄漏。
说实话,这很尴尬。

起初我以为可以使用runOnUiThread,但后来我发现这是错误的。
在高并发情况下,会出现大量重叠更新,导致界面闪烁。
等等,还有一件事,处理程序必须小心地跨进程传递,否则会出现线程安全问题 - 我们去年采用第三方 SDK 时解决了这个漏洞。

建议尝试LiveData+ViewModel模式,该模式包含内部线程的切换逻辑,但要注意ViewModel的生命周期管理。

求助:为什么工作线程不能操作UI线程的控件

上次我帮朋友调试应用程序时,他的界面一团糟。
当你盯着屏幕时,感觉按钮和标签正在跳踢踏舞,变成红色和绿色,然后消失一两秒钟。
他挠了挠头,说道:“我只是想加个动画,怎么就卡住了?”我仔细观察,发现代码中的许多后台线程正在直接移动 UI 元素。
原来这就是UIKit的心情。

例如,在上次测试中我故意更改了主线程之外的按钮的颜色。
你猜怎么着?这个按钮的颜色就像坐过山车一样:首先突然变暗,然后变回原来的浅蓝色,最后完全变成灰色。
我检查了调试器,发现后台线程A被设置为蓝色,主线程同时被设置为灰色,不关心谁先来。
这就像两个人同时拉动同一条风筝线。
风筝当然会飞来飞去。

iOS 4 之后,Apple添加了一些线程安全的方法。
UIColor 和 UIFont 等类现在可以跨线程使用。
但就像上次我更改 UILabel 的字体一样,我仍然必须在主线程上执行此操作。
一旦添加代码行 [label setFont:myFont onThread:1 ],崩溃日志就会包含“UITextStorage was linked in a后台线程”字样。
这让我想起了一个笑话:当苹果说“现在是线程安全的”时,就好像在说“现在发生车祸时会自动报警”。
听起来不错,但还是要小心。

等一下,我突然想到了自定义视图的例子。
上次用动画写图的时候,我把绘图逻辑丢到了后台线程中,发现每次更新的时候,绘制的路径就像是手抖的铅笔画出来的。
当时我以为是显卡的问题,后来发现是因为path对象在后台被改变了,在主线程渲染的时候就过期了。
这就像将水倒入一杯水中并堵住玻璃的开口一样。
最终,杯子永远不会满。

虽然CoreGraphics有.concurrent版本,但就像拆卸自行车零件并使用其他螺丝一样,您仍然需要弄清楚应该先安装谁,应该稍后安装谁。
上次测试多线程绘制,我把路径操作和渲染分开,先计算后台所有的点,最后一次性在主线程上绘制,一下子就流畅了。
这让我想起了一句老话:有时候最省力的方法就是最费力的方法。