什么是AsyncTask的“ UI交互”?

时间:2019-10-14 20:50:08

标签: android user-interface android-asynctask

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

我的问题:禁止UI交互的示例有哪些?可能是以下任何一种情况吗?

  • LayoutInflater.inflate()
  • View.findViewById()
  • TextView.setText()

我倾向于说是,但是我们现在有一些代码可以执行所有这些(以及更多操作),并且可以从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)

1 个答案:

答案 0 :(得分:1)

AsyncTask并不意味着需要很长时间的工作,它应该在几秒钟内完成。它是一站式完全托管的线程上下文,不应附加自己的Looper。实际上,这将破坏支持AsyncTask的功能-使您将来可能开始的其他AsyncTask操作陷入饥饿。如果您有需要Looper的内容,则应该使用自己的ThreadThreadPool而不是AsyncTask。您还需要确保保留对AsyncTask的引用,以便可以将其适当地取消-这是导致许多内存泄漏和/或由于调用onPostExecute()时由于无效状态而导致异常的原因

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

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