AsyncTask 的 "UI interactions" 是什么?

What constitutes "UI interactions" for AsyncTask?

AsyncTask 是在后台线程上异步执行长 运行 操作而不占用 UI 线程的标准方法。不应从 doInBackground() 方法执行任何 UI 交互。

我的问题:UI 禁止互动的例子有哪些?会不会是以下任何一种:

我倾向于说是,但我们现在有一些代码可以完成所有这些(以及更多)并从 doInBackground() 方法调用,但代码仍在运行。我看到其他人表示他们在尝试从 doInBackground() 执行 UI activity 时收到异常,但这不是我们的经验。

我们的代码正在生成一个屏幕报告,该报告在整个操作完成之前是不可见的。在极少数情况下(难以重现)当尝试非常迅速地取消操作时,我们会看到应用程序进入一种奇怪的状态,但它不会崩溃。

在更改我们的代码以期找到这种罕见情况之前,我想看看是否有人对为什么我们的代码保持原样 "working" 有一些想法。

唯一可能有用的信息是我们的 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 交互合法。

(我确实有一个堆栈跟踪,清楚地显示了我们的 UI activity 是从 doInBackground 调用的,以防您认为我们可能会分离一些单独的线程来更新我们的 UI)

AsyncTask 并不意味着很长的 运行ning 工作,它应该在几秒钟内完成。它是一次性完全托管的线程上下文,不应该有自己的 Looper 附加到它。这实际上会破坏支持 AsyncTask 功能 - 使您将来可能开始的其他 AsyncTask 操作挨饿。如果您有需要 Looper 的东西,您应该使用自己的 ThreadThreadPool 而不是 AsyncTask。您还需要确保保留对 AsyncTask 的引用,以便可以适当地取消它 - 这是许多内存泄漏的来源 and/or 由于 onPostExecute() 时的无效状态导致的异常被调用。

publishProgress() 方法的目的是让您的应用能够获取可以反映在用户体验上的更新。你是对的,setText()等在doInBackground()回调中不应该是运行。该回调在您无法控制且无法进行 UI 更新的任意线程上下文中执行。

您也许可以使用 inflateLayout()findViewById(),但在初始化之外执行此操作不是一个好的做法,因为这些操作可能代价高昂。 Inflation 必须解析二进制布局并即时创建视图对象。按 ID 查找遍历整个视图层次结构以查找所需的组件。更好的做法是在创建时缓存它们(对于 ActivityFragment)或在创建视图作为适配器的一部分时(例如 RecyclerView 中的 ViewHolder .