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

时间:2013-06-04 08:11:06

标签: java android android-asynctask

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

public final Result get ()

Waits if necessary for the computation to complete, and then retrieves its result. 

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

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

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

9 个答案:

答案 0 :(得分:18)

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

更新:在回复评论时,为了强调这可能是对AsyncTask.get()的有效使用,可以采取以下措施:

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

KickOffAsynctask(...)

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

答案 1 :(得分:5)

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

我建议将回调或eventbus作为替代品。

答案 2 :(得分:5)

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

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

答案 3 :(得分:4)

我通常使用处理程序类来处理技巧(加载媒体异步)。 像:

public void setRightSongAdele(Song current)
{
    RetriveCorrelateGenreSong rcgs = new RetriveCorrelateGenreSong(current);
    new Thread(rcgs).start();
}

@SuppressLint("HandlerLeak")
Handler updateRightAdeleHandler = new Handler()
{
    @Override
     public void handleMessage(Message msg) {
        songNextText.setText(utils.reduceStringLength(rightSong.getTitle(), 15));
        adeleNext.setImageBitmap(utils.getAlbumArtFromSong(rightSong.getPath(), getApplicationContext()));
    }
};

答案 4 :(得分:3)

我发布了自己的答案,因为这是我现在想的,没有人给出它。

我的好奇心仍然存在,所以我不认为这个是正确的。如果有人出色地回答了这个问题,我会将他/她的回答标记为正确。

我的回答是,实际上没有使用AsyncTask的get()方法是最好的解决方案。

恕我直言,使用这种方法毫无意义。我的意思是似乎总有更好的解决方案。

同样地,我会说它在语义上令人震惊,因为调用它会将AsyncTask更改为有效的“SyncTask”。

答案 5 :(得分:2)

正如文件所示:

  

“如果需要等待计算完成,然后   检索其结果。“

因此,您必须避免在UI线程上调用它,否则您将获得NetworkOnMainThreadException。我会在测试环境中使用它,它涉及网络操作或等待另一项任务完成。

编辑:我对NetworkOnMainThreadException错了。

答案 6 :(得分:2)

似乎AsyncTask.get()阻塞了调用程序线程,AsyncTask.execute()没有。

您可能希望将AsyncTask.get()用于要测试特定Web Service调用的测试用例,但不需要它是异步的,并且您希望控制完成所需的时间。或者,您希望在测试套件中测试您的Web服务。

语法与execute:

相同
    private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
    }

new DownloadFilesTask().get(5000, TimeUnit.MILLISECONDS);

答案 7 :(得分:0)

您可以在AutoCompleteTextView适配器过滤器中使用它。

private class Adapter extends BaseAdapter implements Filterable{
    getFilter(){
        return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            List<String> suggestions = MyApiSuggestionsApi(constraint).get();
            return packageAsFilterResults(suggestions);
        }
    }
}

答案 8 :(得分:-1)

我有一个编辑照片的应用程序,用户可以从URL打开照片。

我使用AsyncTask从URL下载照片,在此期间应阻止UI。我做的是我展示了ProgressBar启动AsyncTask的get()方法而不是隐藏ProgressBar ..

这对我来说似乎是最好最简单的解决方案。