Android执行的asynchronous任务

这是在Android的采访中被问到的。 我被问到是否可以从asynchronous任务1的doInBackground()方法启动另一个asynchronous任务(让它成为Task2)(让它成为Task1)。 我经历了以下的文档:

任务实例必须在UI线程上创build。

必须在UI线程上调用execute(Params …)。

根据这些陈述,我认为应该不可能从另一个任务的后台方法开始一个任务。 另外,asynchronous任务有UI方法(不能在后台线程中使用),所以强化了我的观点,我认为这是不可能的。

在检查一个简单的演示应用程序时,我发现确实有可能这样做。 一些演示代码:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; init(); Log.v ("gaurav", "Thread is : " + Thread.currentThread().getName()); Task1 task = new Task1(); task.execute(); } class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName()); Task2 task = new Task2(); task.execute(); return null; } } class Task2 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName()); Log.v ("gaurav", "Task 2 started"); return null; } } 

我得到以下日志表明成功执行:

 > 08-07 09:46:25.564: V/gaurav(2100): Thread is : main 08-07 > 09:46:25.564: V/gaurav(2100): Thread task 1 is : AsyncTask #3 08-07 > 09:46:25.564: V/gaurav(2100): Thread task 2 is : AsyncTask #4 08-07 > 09:46:25.564: V/gaurav(2100): Task 2 started 

我已经在ICS,KK和L设备上检查过了,它可以正常工作。

我能想到的一个原因是,我不是覆盖任何UI方法,并在我的第二个任务中做任何UI更新,因此它不会造成任何问题,但我不确定。 即使是这样,它也违反了开发人员指南中提到的线程规则。

作为一个参考,我也检查了这个链接: 从另一个AsyncTask doInBackground()启动AsyncTask,但答案指出使用doInBackground()内的runOnUiThread()方法启动第二个任务。 我想在这里发生一些帮助。 谢谢。

Solutions Collecting From Web of "Android执行的asynchronous任务"

让我们将您的代码更改为以下内容:

 class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 1 is : " + Thread.currentThread().getName()); Task2 task = new Task2(); task.execute(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Log.v ("gaurav", "Log after sleeping"); return null; } } class Task2 extends AsyncTask { @Override protected Object doInBackground(Object... params) { // TODO Auto-generated method stub Log.v ("gaurav", "Thread task 2 is : " + Thread.currentThread().getName()); Log.v ("gaurav", "Task 2 Started"); return null; } } 

现在LogCat返回:

 08-07 06:13:44.208 3073-3073/testapplication V/gaurav﹕ Thread is : main 08-07 06:13:44.209 3073-3091/testapplication V/gaurav﹕ Thread task 1 is : AsyncTask #1 08-07 06:13:49.211 3073-3091/testapplication V/gaurav﹕ Log after sleeping 08-07 06:13:49.213 3073-3095/testapplication V/gaurav﹕ Thread task 2 is : AsyncTask #2 08-07 06:13:49.213 3073-3095/testapplication V/gaurav﹕ Task 2 Started 

正如你所看到的, Task 2Task 1执行结束后执行(甚至在睡眠5秒后)。 这意味着第二项任务在第一项任务完成之前不会开始。

为什么? 原因在于AsyncTask的源代码背后。 请考虑execute()方法:

 public synchronized void execute(final Runnable r) { mTasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (mActive == null) { scheduleNext(); } } 

scheduleNext()方法:

 protected synchronized void scheduleNext() { if ((mActive = mTasks.poll()) != null) { THREAD_POOL_EXECUTOR.execute(mActive); } } 

这些方法中最重要的关键字是synchronized ,确保这些方法只能在一个线程中同时运行。 当你调用execute方法时,它提供了一个新的mTask Runnable ,它是ArrayDeque<Runnable>类的一个实例,它作为不同线程的不同请求的序列化程序[更多信息] 。 如果没有执行Runnable (即if (mActive == null) ),则调用scheduleNext() ,否则finally块中的scheduleNext()将在当前执行的Runnable (由于任何原因) 。 所有的Runnable都在THREAD_POOL_EXECUTOR一个单独的线程上执行。

从其他线程执行AsyncTask有什么问题? 从Jelly Bean开始,一个AsyncTask在UI线程的应用程序启动时被class加载,以保证在UI线程上发生callback,但是在Jelly Bean发布之前,如果另一个线程创build了AsyncTask ,callbackAsyncTask 可能会不会在正确的线程上发生。

所以, AsyncTask实现只能在Jelly Bean( +和+ )之前的平台上从UI线程调用。


澄清:请考虑下面的例子,只是澄清Android的不同平台版本之间的差异:

 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); new Thread() { @Override public void run() { Task1 task = new Task1(); task.execute(); } }.start(); } class Task1 extends AsyncTask { @Override protected Object doInBackground(Object... params) { return null; } } 

它在Android 5.1上工作正常,但在Android 2.3上出现以下exception:

 08-07 12:05:20.736 584-591/github.yaa110.testapplication E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-8 java.lang.ExceptionInInitializerError at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21) Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at android.os.Handler.<init>(Handler.java:121) at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421) at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421) at android.os.AsyncTask.<clinit>(AsyncTask.java:152)            at github.yaa110.testapplication.Main2Activity$1.run(Main2Activity.java:21)