同时运行多个AsyncTasks – 不可能?

我试图同时运行两个AsyncTasks。 (平台是Android 1.5,HTC Hero。)但是,只有第一个被执行。 这里有一个简单的片段来描述我的问题:

public class AndroidJunk extends Activity { class PrinterTask extends AsyncTask<String, Void, Void> { protected Void doInBackground(String ... x) { while (true) { System.out.println(x[0]); try { Thread.sleep(1000); } catch (InterruptedException ie) { ie.printStackTrace(); } } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new PrinterTask().execute("bar bar bar"); new PrinterTask().execute("foo foo foo"); System.out.println("onCreate() is done."); } } 

我期望的结果是:

 onCreate() is done. bar bar bar foo foo foo bar bar bar foo foo foo 

等等。 但是,我得到的是:

 onCreate() is done. bar bar bar bar bar bar bar bar bar 

第二个AsyncTask永远不会被执行。 如果我改变了execute()语句的顺序,那么只有foo任务会产生输出。

我在这里错过了一些明显的东西,或者做了些什么愚蠢的事情? 是不是可以同时运行两个AsyncTasks?

编辑:我意识到有问题的手机运行Android 1.5,我更新了问题descr。 因此。 运行Android 2.1的HTC Hero没有这个问题。 嗯…

AsyncTask使用线程池模式来运行doInBackground()中的东西。 这个问题最初(在早期的Android操作系统版本中)池大小只是1,这意味着一堆AsyncTasks没有并行计算。 但后来他们修复了这个问题,现在的大小是5,所以至多5个AsyncTasks可以同时运行。 不幸的是我不记得他们改变了什么版本。

更新:

以下是目前(2012-01-27)AP​​I所说的:

第一次引入时,AsyncTasks在单个后台线程上被串行执行。 从DONUT开始,将其更改为允许多个任务并行操作的线程池。 在HONEYCOMB之后,计划将其改回单线程以避免由于并行执行而导致的常见应用程序错误。 如果您确实需要并行执行,则可以使用THREAD_POOL_EXECUTOR的此方法的executeOnExecutor(Executor,Params …)版本; 然而,请参阅评论那里使用的警告。

DONUT是Android 1.6,HONEYCOMB是Android 3.0。

更新:2

Mar 7 at 1:27看到kabuko的评论。

事实certificate,对于使用“允许多个任务并行操作的线程池”的API(从1.6开始到3.0结束),同时运行的AsyncTasks的数量取决于已经有多less个任务已经被执行,但是还没有完成他们的doInBackground()呢。

这是我在2.2testing/确认的。 假设你有一个自定义的AsyncTask,它只是在doInBackground()hibernate一秒钟。 AsyncTasks在内部使用固定大小的队列来存储延迟的任务。 队列大小默认为10。 如果你在一行中启动15个自定义任务,那么前5个将进入他们的doInBackground() ,但剩下的将在队列中等待一个空闲的工作线程。 只要前5个任务中的任何一个完成,从而释放一个工作线程,队列中的任务将开始执行。 所以在这种情况下,最多5个任务将同时运行。 但是,如果你在一行中启动16个自定义任务,那么前5个将进入他们的doInBackground() ,剩下的10个将进入队列,但是在16日,将会创build一个新的工作线程,以便立即开始执行。 所以在这种情况下,最多6个任务将同时运行。

有多less任务可以同时运行的限制。 由于AsyncTask使用最大工作线程数量有限的线程池执行程序(128),而延迟任务队列的大小固定为10,所以如果尝试执行超过138个自定义任务,应用程序将使用java.util.concurrent.RejectedExecutionException

从3.0开始,API允许通过AsyncTask.executeOnExecutor(Executor exec, Params... params)方法使用自定义线程池执行程序。 例如,这允许configuration延迟任务队列的大小,如果默认10不是你所需要的。

正如@Knossos提到的,有一个选项可以使用AsyncTaskCompat.executeParallel(task, params); 从支持v.4库到并行运行任务,不用打扰API级别。 此方法在API级别26.0.0中已被弃用。

更新:3

这里是一个简单的testing应用程序,玩的任务数量,序列与并行执行: https : //github.com/vitkhudenko/test_asynctask

更新:4 (感谢@penkzhou指出这一点)

从Android 4.4开始, AsyncTask行为与UPDATE:2部分中描述的行为不同。 有一个修复,以防止AsyncTask创build太多的线程。

在Android 4.4(API 19)之前, AsyncTask具有以下字段:

 private static final int CORE_POOL_SIZE = 5; private static final int MAXIMUM_POOL_SIZE = 128; private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(10); 

在Android 4.4(API 19)中,上面的字段被更改为:

 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); private static final int CORE_POOL_SIZE = CPU_COUNT + 1; private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); 

此更改会将队列的大小增加到128个项目,并将线程的最大数量减less到CPU内核数量* 2 + 1。应用程序仍然可以提交相同数量的任务。

这允许在API 4+(Android 1.6+)的所有Android版本上并行执行:

 @TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11 void startMyTask(AsyncTask asyncTask) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); else asyncTask.execute(params); } 

这是Arhimed的出色答案的总结。

请确保您使用API​​级别11或更高作为您的项目构build目标。 在Eclipse中,即Project > Properties > Android > Project Build Target不会将向后兼容性分解为更低的API级别。 不要担心,如果意外使用晚于minSdkVersion引入的function,则会出现Lint错误。 如果您真的想使用晚于minSdkVersion引入的function,则可以使用注释来抑制这些错误,但在这种情况下,您需要自己考虑兼容性。 这正是上面代码片段中发生的事情。

使@sulaibuild议更通用:

 @TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11 public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); else asyncTask.execute(params); } 

Android开发人员高效地使用加载位图的示例使用自定义的asynctask(从jellybean复制),所以你可以在apis下使用executeOnExecutor <11

http://developer.android.com/training/displaying-bitmaps/index.html

下载代码并转到util包。

这是可能的。 我的Android设备版本是4.0.4和android.os.Build.VERSION.SDK_INT是15

我有3个纺纱工

 Spinner c_fruit=(Spinner) findViewById(R.id.fruits); Spinner c_vegetable=(Spinner) findViewById(R.id.vegetables); Spinner c_beverage=(Spinner) findViewById(R.id.beverages); 

而且我还有一个Async-Tack类。

这是我的微调加载代码

 RequestSend reqs_fruit = new RequestSend(this); reqs_fruit.where="Get_fruit_List"; reqs_fruit.title="Loading fruit"; reqs_fruit.execute(); RequestSend reqs_vegetable = new RequestSend(this); reqs_vegetable.where="Get_vegetable_List"; reqs_vegetable.title="Loading vegetable"; reqs_vegetable.execute(); RequestSend reqs_beverage = new RequestSend(this); reqs_beverage.where="Get_beverage_List"; reqs_beverage.title="Loading beverage"; reqs_beverage.execute(); 

这是完美的工作。 一个一个的我的纺纱人员装载。 我没有用户executeOnExecutor。

这是我的asynchronous任务类

 public class RequestSend extends AsyncTask<String, String, String > { private ProgressDialog dialog = null; public Spinner spin; public String where; public String title; Context con; Activity activity; String[] items; public RequestSend(Context activityContext) { con = activityContext; dialog = new ProgressDialog(activityContext); this.activity = activityContext; } @Override protected void onPostExecute(String result) { try { ArrayAdapter<String> adapter = new ArrayAdapter<String> (activity, android.R.layout.simple_spinner_item, items); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spin.setAdapter(adapter); } catch (NullPointerException e) { Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show(); e.printStackTrace(); } catch (Exception e) { Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show(); e.printStackTrace(); } super.onPostExecute(result); if (dialog != null) dialog.dismiss(); } protected void onPreExecute() { super.onPreExecute(); dialog.setTitle(title); dialog.setMessage("Wait..."); dialog.setCancelable(false); dialog.show(); } @Override protected String doInBackground(String... Strings) { try { Send_Request(); } catch (NullPointerException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } public void Send_Request() throws JSONException { try { String DataSendingTo = "http://www.example.com/AppRequest/" + where; //HttpClient HttpClient httpClient = new DefaultHttpClient(); //Post header HttpPost httpPost = new HttpPost(DataSendingTo); //Adding data List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); nameValuePairs.add(new BasicNameValuePair("authorized","001")); httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); // execute HTTP post request HttpResponse response = httpClient.execute(httpPost); BufferedReader reader; try { reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); StringBuilder builder = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { builder.append(line) ; } JSONTokener tokener = new JSONTokener(builder.toString()); JSONArray finalResult = new JSONArray(tokener); items = new String[finalResult.length()]; // looping through All details and store in public String array for(int i = 0; i < finalResult.length(); i++) { JSONObject c = finalResult.getJSONObject(i); items[i]=c.getString("data_name"); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } 

只需在@Arhimed的完美摘要中包含最新更新(更新4)@sulai的非常好的摘要:

 void doTheTask(AsyncTask task) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Android 4.4 (API 19) and above // Parallel AsyncTasks are possible, with the thread-pool size dependent on device // hardware task.execute(params); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Android 3.0 to // Android 4.3 // Parallel AsyncTasks are not possible unless using executeOnExecutor task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); } else { // Below Android 3.0 // Parallel AsyncTasks are possible, with fixed thread-pool size task.execute(params); } } 

如果你想并行执行任务,你需要在Android版本3.0之后调用方法executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name") ; 但是这个方法在Android 3.0和1.6之后是不存在的,因为它本身并行执行,所以我build议你在你的项目中定制你自己的AsyncTask类,以避免在不同的Android版本中抛出exception。