我试图同时运行两个 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 任务会产生输出。

我在这里错过了一些明显的事情和/或做了一些愚蠢的事情吗?不能同时运行两个AsyncTask吗?

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

有帮助吗?

解决方案

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

更新:

以下是当前 (2012-01-27) API 对此的说法:

首次引入时,AsyncTasks 在单个后台线程上串行执行。从 DONUT 开始,这被更改为线程池,允许多个任务并行操作。在HONEYCOMB之后,计划将其改回单线程,以避免并行执行导致的常见应用程序错误。如果你确实想要并行执行,你可以将此方法的executeOnExecutor(Executor, Params...) 版本与THREAD_POOL_EXECUTOR 结合使用;但是,请参阅那里的评论以获取有关其使用的警告。

DONUT是Android 1.6,HONEYCOMB是Android 3.0。

更新:2

查看评论者 kabukoMar 7 at 1:27.

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

这是我在 2.2 上测试/确认的。假设您有一个自定义 AsyncTask,它只休眠一秒钟 doInBackground(). 。AsyncTasks 在内部使用固定大小的队列来存储延迟任务。队列大小默认为 10。如果您连续启动 15 个自定义任务,那么前 5 个将输入它们的任务 doInBackground(), ,但其余的将在队列中等待空闲的工作线程。一旦前 5 个任务完成并释放工作线程,队列中的任务就会开始执行。因此在这种情况下最多会同时运行 5 个任务。但是,如果您连续启动 16 个自定义任务,那么前 5 个将输入它们的任务 doInBackground(), ,其余 10 个将进入队列,但第 16 个将创建一个新的工作线程,因此它将立即开始执行。所以在这种情况下最多 6 个任务会同时运行。

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

从 3.0 开始,API 允许通过以下方式使用自定义线程池执行器 AsyncTask.executeOnExecutor(Executor exec, Params... params) 方法。例如,如果您不需要默认值 10,则可以配置延迟任务队列的大小。

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

更新:3

这是一个简单的测试应用程序,用于处理任务数量、串行与并行任务。并行执行: https://github.com/vitkhudenko/test_asynctask

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

从安卓4.4开始 AsyncTask 行为与所描述的不同 更新:2 部分。那里 是一个修复 阻止 AsyncTask 因为创建了太多线程。

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 个项目,并将最大线程数减少到 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 或更高版本作为您的项目构建目标。在 Eclipse 中,即 Project > Properties > Android > Project Build Target. 这会 不是 破坏对较低 API 级别的向后兼容性。 别担心,如果您不小心使用了之后引入的功能,您将收到 Lint 错误 minSdkVersion. 。如果您确实想使用稍后推出的功能 minSdkVersion, ,您可以使用注释来抑制这些错误,但在这种情况下,您需要注意兼容性 你自己. 。这正是上面代码片段中发生的情况。

制作@sulai建议更通用的:

@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);
}   

就包括最新的更新(UPDATE 4)@Arhimed的完美答案@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开发者有效地例如使用自定义的AsyncTask(来自豆形软糖复制),所以可以使用在executeOnExecutor的API低于<11

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

下载的代码,并转到util包。

有更多钞票。 我的机器人装置的版本是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);

和还我一个异步粘性类。

下面是我的纺丝器加载代码

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。

下面是我的异步任务类

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();
        }
    }
}

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top