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

2022-09-02 09:19:59

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

public final Result get ()

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

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

除了测试目的,即使在这些情况下,我也无法真正认为它实际上是一个好的解决方案,但我可能是错的,所以我感到好奇。

如果需要用户实际等待 AsyncTask 完成,则可以显示对话框或进度对话框,并在每时每刻都控制 UI。我知道这并不完全相同,但恕我直言,这是一种比使用该方法更好的方法。get()


答案 1

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

更新:作为对注释的回应,为了强调这可能是 的有效用法,以下是可能的:AsyncTask.get()

  • 可能有一些是从UI线程启动的,这可能涉及通过Internet进行通信,例如加载网页或与服务器通信。无论结果如何,都需要一些(或全部)结果来更新屏幕。因此,在 UI 线程上后跟 a 是有意义的。AsyncTaskAsyncTaskAsyncTaskdoInBackgroundonPostExecute
  • 每当 UI 线程启动 时,它都会将对象放在队列中,以便在结果可用后由单独的后台线程进行其他处理。AsyncTaskAsyncTask
  • 对于队列中的每个线程,后台线程在执行其他处理之前,将使用等待任务完成。额外处理的一个明显示例可能只是将所有此类活动记录到Internet上的服务器,因此在后台执行此操作是有意义的。AsyncTaskAsyncTask.get()AsyncTask
下面的代码显示了我的意思。每当应用想要执行 AsyncTask 时,它就会调用,并且有一个后台线程,该线程将在任务完成后自动选取任务进行后处理。KickOffAsynctask(...)
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();
            }           
        }

    }

}

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


答案 2

该方法不应在 UI 线程中使用,因为它会(如你所注意到的)冻结你的 UI。它应该在后台线程中使用以等待任务结束,但一般来说,尽量避免(为什么?getAsyncTask

我建议使用回调或事件总线作为替代。


推荐