AsyncTask的get()方法:是否有任何情况下它实际上是最佳选择?

Ale*_*ado 20 java android android-asynctask

回答完这个问题之后,我对使用Android的AsyncTask类的get()方法的意义/用处产生了疑问.

public final Result get ()

Waits if necessary for the computation to complete, and then retrieves its result. 
Run Code Online (Sandbox Code Playgroud)

基本上,AsyncTask类的同步解决方案,阻止(冻结)UI直到后台操作完成.

除了测试目的,甚至在那些情况下,我无法真正想到它实际上是一个很好的解决方案,但我可能是错的,所以我感到好奇.

如果您需要用户实际等到AsyncTask完成,您可以显示Dialog或ProgressDialog,在每个时刻都可以控制UI.我知道它不完全相同,但恕我直言,它比使用该get()方法更好的方法.

Sto*_*lly 18

AsyncTask不是进行后台操作的唯一方法.实际上,文档说AsyncTask只应该用于操作最多只需几秒钟.因此,如果您的任务需要更长时间,则应通过实现可运行接口的类对其进行编码.其他(非AsyncTask)线程中的此类任务可能希望等待AsyncTask完成,因此在我看来,没有人想要使用的情况AsyncTask.get()是错误的.

更新:在回复评论时,为了强调这可能是一种有效的用途AsyncTask.get(),以下是可能的:

  • 可能存在AsyncTask从UI线程发起的,其可能涉及通过因特网进行通信,例如加载网页或与服务器通信.无论结果是什么AsyncTask,都需要一些(或全部)结果来更新屏幕.因此AsyncTask,它doInBackground跟随onPostExecuteUI线程是有意义的.
  • 每当UI线程启动时AsyncTask,它都会将AsyncTask对象放入队列中,以便在结果可用后由单独的后台线程进行额外处理.
  • 对于AsyncTask队列中的每个队列,后台线程用于AsyncTask.get()等待任务完成,然后再执行其他处理.一个明显的额外处理示例可能只是将所有此类AsyncTask活动记录到Internet上的服务器,因此在后台执行此操作是有意义的.
以下代码显示了我的意思.应用程序KickOffAsynctask(...)在想要执行AsyncTask时调用,并且有一个后台线程,一旦任务完成,它将自动拾取任务以进行后处理.

public class MyActivity extends Activity {

    static class MyAsyncTaskParameters { }
    static class MyAsyncTaskResults { }

    Queue<MyAsyncTask> queue;   // task queue for post-processing of AsyncTasks in the background
    BackgroundThread b_thread;  // class related to the background thread that does the post-processing of AsyncTasks

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        queue = new  ConcurrentLinkedQueue<MyAsyncTask>();
        b_thread = new BackgroundThread(queue);
        b_thread.Start();       
    }

    void KickOffAsynctask(MyAsyncTaskParameters params) {
        MyAsyncTask newtask = new MyAsyncTask();
        newtask.execute(params);
        synchronized(queue) {
            queue.add(newtask);
        }
    }

    static class MyAsyncTask extends AsyncTask<MyAsyncTaskParameters, Void, MyAsyncTaskResults> {

        @Override
        protected MyAsyncTaskResults doInBackground(MyAsyncTaskParameters... params) {
            MyAsyncTaskResults results = new MyAsyncTaskResults();
            // do AsyncTask in background
            return results;
        }

        @Override
        protected void onPostExecute(MyAsyncTaskResults res){
            // take required results from MyAsyncResults for use in the user interface
        }

    }

    static class BackgroundThread implements Runnable {
        // class that controls the post processing of AsyncTask results in background

        private Queue<MyAsyncTask> queue;
        private Thread thisthread;
        public boolean continue_running;

        public BackgroundThread(Queue<MyAsyncTask> queue) {
            this.queue=queue; thisthread = null; continue_running = true;
        }

        public void Start() {
            thisthread = new Thread(this);
            thisthread.start();
        }

        @Override
        public void run() {
            try {
                do {
                    MyAsyncTask task;
                    synchronized(queue) {
                        task = queue.poll();
                    }
                    if (task == null) {
                        Thread.sleep(100);
                    } else {
                        MyAsyncTaskResults results = task.get();
                        // post processing of AsyncTask results in background, e.g. log to a server somewhere
                    }
                } while (continue_running);     
            } catch(Throwable e) {
                e.printStackTrace();
            }           
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

Update2.我发现了另一种可能的有效用途AsyncTask.get().标准建议不是AsyncTask.get()从UI线程使用,因为它会导致用户界面冻结,直到结果可用.但是,对于需要隐身的应用程序,这可能正是所需要的.那么下面的情况如何:詹姆斯·邦德闯入Le Chiffre的酒店房间,只有几分钟的时间从villian手机中提取所有数据并安装监控病毒.他安装Q提供的应用程序并开始运行,但他听到有人来,所以他必须隐藏. Le Chiffre进入房间然后拿起电话拨打电话.几秒钟后,手机似乎有点反应迟钝,但突然手机响起,他不停地想着打电话.当然,没有反应的原因是Q的应用程序正在运行.它有各种各样的任务要做,其中一些需要按特定的顺序完成.该应用程序使用两个线程来完成工作,即UI线程本身和处理AsyncTasks 的单个后台线程.UI线程完全控制所有任务,但由于某些任务需要在其他任务之前完成,因此AsyncTask.get()在等待后台任务完成时使用的UI线程中存在点:-).


AMe*_*rle 5

get永远不要在UI线程中使用该方法,因为它会(如您所见)冻结您的UI.它应该在后台线程中用于等待任务的结束,但一般来说,尽量避免AsyncTask(为什么?).

我建议使用回调或eventbus作为替代品.

  • 正如[官方文档](http://developer.android.com/reference/android/os/AsyncTask.html)所述:`理想情况下,AsyncTasks应该用于短操作(最多几秒钟).如果需要为了保持线程长时间运行,强烈建议您使用java.util.concurrent pacakge提供的各种API,例如Executor,ThreadPoolExecutor和FutureTask. (3认同)

and*_*per 5

如果并行运行多个asyncTasks,您可能希望某些任务等待其他任务的结果.

但是,我认为你应该避免并行运行太多asyncTasks,因为它会降低设备速度.