从自定义视图启动AsyncTask的最佳实践 [英] Best practice to launch AsyncTask from custom view

查看:142
本文介绍了从自定义视图启动AsyncTask的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是很常见的催生一个耗时的计算线程。后来,我们需要更新活动片段与计算结果。

在这期间,我跟随下面的指导方针。它很适合我到现在。

的AsyncTask需要onPostExecute UI片段


  1. 使用 setRetainInstance(真) UI少片段。

  2. 使用 setTargetFragment getTargetFragment 技术

  3. 请参见 http://stackoverflow.com/a/12303649/72437

的AsyncTask需要onPostExecute界面活性


  1. 使用 setRetainInstance(真) UI少片段。

  2. 使用 onAttach onDetach 来保存引用活动。谷歌似乎不鼓励使用 getActivity http://developer.android.com/guide/components/fragments.html

  3. 请参见 http://stackoverflow.com/a/16305029/72437

然而,怎么样的情况下从查看派生的类?我计划从自定义查看推出的AsyncTask 。但是,我怎么能 onPostExecute 查看

我问所以,在我的自定义视图的原因,某些触摸事件将触发其与新的位图重绘自身。产生新的位图是耗时的。因此,我计划推出的AsyncTask,产生这样的位图,并传回自定义视图。但是,配置更改可能导致自定义视图重新创建。因此,我需要确保我的AsyncTask能有正确的看法时参考 onPostExecute


解决方案

假设你使用的AsyncTask 只为绘图相关的操作(​​否则你真的应该重新审视你的逻辑 - 作为意见建议),您可以创建的AsyncTask 在自定义直接查看类:

 类MyView的扩展视图{    私人MyAsyncTask currentTask = NULL;    // 查看详情    @覆盖
    公共无效onAttachedToWindow(){
        currentTask =新MyAsyncTask(本);
        currentTask.execute();
    }    @覆盖
    公共无效onDetachedFromWindow(){
        super.onDetachedFromWindow();
        如果(currentTask!= NULL){
            currentTask.cancel(真);
            currentTask = NULL;
        }
    }    静态类MyAsyncTask扩展的AsyncTask<无效,无效的,位图> {        私人的WeakReference<&MyView的GT; viewRef;        MyAsyncTask(MyView的视图){
            viewRef =新的WeakReference<>(视图);
        }        //后台任务落实        @覆盖
        公共无效onPostExecute(位图位图){
            MyView的观点= viewRef.get();
            如果(查看== NULL){
                返回;
            }            //你现在可以安全地更新你的观点 - 我们是在UI线程
        }    }}

这是如何实现安全会是什么样子。它也有一些缺点和重要的部分:


  • 在任何时候你的的AsyncTask 应该持有强引用查看(这就是为什么类被声明为静态并持有的WeakReference 查看

  • 当您从的AsyncTask 不感兴趣,结果了 - 取消

  • 这实现将扔掉可能有用的结果,从取消的AsyncTask 。如果是这样的问题 - 我建议删除的AsyncTask 查看完全和寻找其他的解决方案(单独执行人 HandlerThread )。

还有 onPostExecute 的AsyncTask 将被从启动它的同一弯针线所谓的(在你的情况这是主线程,因此它不会,如果你从活动查看,或任何其他地方启动它没关系,这一切都取决于这将是多么难以管理的任务)。

It is quite common to spawn a time consuming computation thread. Later, we require to update Activity or Fragment with computation result.

All the while, I'm following the below guidelines. It works well for me till now.

AsyncTask needs to onPostExecute UI Fragment

  1. Use setRetainInstance(true) UI-less fragment.
  2. Use setTargetFragment and getTargetFragment technique
  3. Please refer to http://stackoverflow.com/a/12303649/72437

AsyncTask needs to onPostExecute UI Activity

  1. Use setRetainInstance(true) UI-less fragment.
  2. Use onAttach and onDetach to store reference to Activity. Google seems doesn't encourage using getActivity. http://developer.android.com/guide/components/fragments.html
  3. Please refer to http://stackoverflow.com/a/16305029/72437

However, how about case for a class derived from View? I plan to launch AsyncTask from the custom View. However, how can I onPostExecute back to the View?

The reason I'm asking so is, in my custom view, certain touch event will trigger it to redraw itself with a new bitmap. Generating the new bitmap is time consuming. Hence, I plan to launch a AsyncTask, to generate such bitmap, and pass back to custom View. However, configuration change might cause custom View to be recreated. Hence, I need to ensure my AsyncTask can have correct View reference during onPostExecute.

解决方案

Assuming that you're using AsyncTask only for drawing-related operations (otherwise you should really revisit your logic - as comments suggest), you can create AsyncTask directly in your custom View class:

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
        }

    }

}

That's how safe implementation would look like. It has some disadvantages and important parts:

  • At no point your AsyncTask should hold strong reference to View (that's why class is declared as static and holds WeakReference to View)
  • When you're not interested in result from AsyncTask anymore - cancel it
  • This implementation will just throw away possibly useful result from cancelled AsyncTask. If that's the issue - I would suggest to remove AsyncTask from View completely and search for others solutions (separate Executor or HandlerThread).

Also onPostExecute of AsyncTask will be called from the same looper thread which launched it (in your case that's main thread, so it does not matter if you start it from Activity or View, or wherever else, it all depends on how hard it would be to manage those tasks).

这篇关于从自定义视图启动AsyncTask的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆