AsyncTask技术疑问:为何可在doInBackground方法中访问布局组件?
嘿,这个问题戳中了Android开发里一个很容易让人困惑的“灰色地带”——明明我们一直被反复强调「后台线程绝对不能操作UI组件」,结果代码居然跑起来了,简直像打破了规则对吧?其实背后是这几个原因:
线程检查不是“实时触发”的:Android里判断UI操作是否在主线程的核心逻辑在
ViewRootImpl.checkThread()方法里,但这个方法并不是你一触碰UI组件就立刻执行的——它只会在View需要被绘制、布局,或者和Window绑定的关键节点才会触发。如果你只是在doInBackground里修改了ProgressBar的进度值,但系统刚好还没走到重绘的流程,那暂时不会触发线程检查,代码就“侥幸”跑通了。View可能还没和UI线程绑定:如果你的AsyncTask是在Activity初始化的早期(比如
onCreate里刚创建完ProgressBar就启动),这时候ProgressBar还没被添加到Window中,ViewRootImpl还没创建出来。没有了ViewRootImpl,自然也就没有线程检查的逻辑,这时候修改View的状态不会触发异常。这是绝对不可依赖的未定义行为:划重点!这次能跑完全是运气,不是合法操作。Android的UI组件是线程不安全的,后台线程操作UI随时可能因为系统调度、Android版本差异、设备不同而抛出
CalledFromWrongThreadException,甚至出现界面错乱、崩溃等难以排查的问题。正确的做法永远是在onProgressUpdate(AsyncTask里)或者用runOnUiThread、Handler把UI操作切回主线程。
内容的提问来源于stack exchange,提问作者Florian Walther

