android - 从自定义 View 启动 AsyncTask 的最佳实践

标签 android android-fragments android-asynctask

产生一个耗时的计算线程是很常见的。稍后,我们需要用计算结果更新 ActivityFragment

一直以来,我都遵循以下准则。到目前为止,它对我来说效果很好。

AsyncTask 需要onPostExecute UI Fragment

  1. 使用 setRetainInstance(true) 无 UI fragment 。
  2. 使用setTargetFragmentgetTargetFragment 技术
  3. 请引用https://stackoverflow.com/a/12303649/72437

AsyncTask 需要 onPostExecute UI Activity
  1. 使用 setRetainInstance(true) 无 UI fragment 。
  2. 使用onAttachonDetach 来存储对Activity 的引用。 Google 似乎不鼓励使用 getActivityhttp://developer.android.com/guide/components/fragments.html
  3. 请引用https://stackoverflow.com/a/16305029/72437

但是,对于从 View 派生的类,情况如何?我计划从自定义 View 启动 AsyncTask。但是,如何onPostExecute 返回View

我这样问的原因是,在我的自定义 View 中,某些触摸事件会触发它使用新的位图重绘自身。生成新位图非常耗时。因此,我计划启动一个 AsyncTask,生成这样的位图,然后传回自定义 View 。但是,配置更改可能会导致重新创建自定义 View 。因此,我需要确保我的 AsyncTask 在 onPostExecute 期间可以有正确的 View 引用。

最佳答案

假设您仅将 AsyncTask 用于与绘图相关的操作(否则您真的应该重新审视您的逻辑 - 正如评论所建议的那样),您可以直接在中创建 AsyncTask您的自定义 View 类:

class MyView extends View {

    private MyAsyncTask currentTask = null;

    // View details

    @Override
    public void onAttachedToWindow() {
        currentTask = new MyAsyncTask(this);
        currentTask.execute();
    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (currentTask != null) {
            currentTask.cancel(true);
            currentTask = null;
        }
    }

    static class MyAsyncTask extends AsyncTask<Void, Void, Bitmap> {

        private WeakReference<MyView> viewRef;

        MyAsyncTask(MyView view) {
            viewRef = new WeakReference<>(view);
        }

        // background task implementation

        @Override
        public void onPostExecute(Bitmap bitmap) {
            MyView view = viewRef.get();
            if (view == null) {
                return;
            }

            // you now can safely update your view - we're on UI thread
        }

    }

}

这就是安全实现的样子。它有一些缺点和重要的部分:

  • 在任何情况下,您的 AsyncTask 都不应持有对 View 的强引用(这就是类被声明为 static 并持有 WeakReference< 的原因View)
  • 当您不再对 AsyncTask 的结果感兴趣时 - 取消它
  • 此实现只会丢弃来自已取消的 AsyncTask 的可能有用的结果。如果这是问题 - 我建议从 View 中完全删除 AsyncTask 并搜索其他解决方案(单独的 ExecutorHandlerThread).

AsyncTaskonPostExecute 也会从启动它的同一个循环线程中调用(在你的例子中是主线程,所以如果你从ActivityView,或其他任何地方,这完全取决于管理这些任务的难度)。

关于android - 从自定义 View 启动 AsyncTask 的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26913133/

相关文章:

android - 在 webview 中打开一个 Sqlite 数据库

java - FirebaseAuth.getInstance().getUid() - 它是如何工作的?

Android Activity 和 Fragment 之间的通信

android - 在 fragment 中实现滑动标签

android - ListView 的多线程使错误的项目/根本没有项目出现

java - 进度条无限旋转

java - 使用cordova发送消息到webview进行处理

java - 异步任务完成后刷新我的 fragment View

java - Android 中的 Realm 异步事务顺序结构

android - 如何使用 ConnectivityManager 通过自定义(ssid 和密码)配置启动 wifi 热点?