AsyncTask是在后台线程上异步执行长时间运行的操作而不占用UI线程的标准方法。不应通过doInBackground()方法执行任何UI交互。
我的问题:禁止UI交互的示例有哪些?可能是以下任何一种情况吗?
我倾向于说是,但是我们现在有一些代码可以执行所有这些(以及更多操作),并且可以从doInBackground()方法中调用,但是代码仍在工作。我见过其他人指出,他们尝试从doInBackground()执行UI活动时会收到异常,但这不是我们的经验。
我们的代码正在生成一个屏幕报告,该报告在整个操作完成之前是不可见的。在极少数情况下(很难重现),当尝试非常快速地取消操作时,我们会看到应用程序进入怪异状态,但不会崩溃。
在更改我们的代码以希望找到这种罕见条件之前,我想看看是否有人对我们的代码为何按原样“工作”的看法。
唯一有用的信息是我们的doInBackground方法具有以下代码模板:
protected Boolean doInBackground(Void... voids) {
if (null == Looper.myLooper()) {
Looper.prepare();
}
publishProgress(0.0);
// Perform ui/non-ui logic here
Looper myLooper = Looper.myLooper();
if (null != myLooper && Looper.getMainLooper() != myLooper) {
myLooper.quit();
}
return true;
}
某些使用 new Handler()生成数据的报告生成代码(省略)需要Looper。我不确定创建Looper是否会以某种方式使我们的ui交互合法化。
(我确实有一个堆栈跟踪,可以清楚地显示从doInBackground调用我们的UI活动,以防您认为我们可能会分离出一些单独的线程来更新我们的UI)
答案 0 :(得分:1)
AsyncTask
并不意味着需要很长时间的工作,它应该在几秒钟内完成。它是一站式完全托管的线程上下文,不应附加自己的Looper
。实际上,这将破坏支持AsyncTask
的功能-使您将来可能开始的其他AsyncTask
操作陷入饥饿。如果您有需要Looper
的内容,则应该使用自己的Thread
或ThreadPool
而不是AsyncTask
。您还需要确保保留对AsyncTask
的引用,以便可以将其适当地取消-这是导致许多内存泄漏和/或由于调用onPostExecute()
时由于无效状态而导致异常的原因
publishProgress()
方法的目的是使您的应用能够获取可以反映在UX上的更新。您是正确的,setText()
等不应在doInBackground()
回调中运行。该回调在您无法控制且无法进行UI更新的任意线程上下文中执行。
您也许可以使用inflateLayout()
和findViewById()
,但是在初始化之外执行此操作不是一个好习惯,因为这些操作可能很昂贵。通货膨胀必须解析二进制布局并动态创建视图对象。按ID查找可遍历整个视图层次结构以查找所需的组件。更好的做法是在创建时(对于Activity
或Fragment
)或在将视图作为适配器的一部分创建时(例如ViewHolder
中的RecyclerView
)将其缓存