2

私のアプリは多くの AsyncTask を使用しています。結局のところ、それはWebアプリです。そして、[デバッグ] タブを追跡すると、すべての AsyncTask がその背後で実行されていることがわかり、5 つの AsyncTask の後、AsyncTask を開始できません。THREAD_POOL_EXECUTOR15 スレッドをプールできるようにエグゼキュータを変更することで修正しました。しかし、AsyncTasks はまだ実行中として表示されます。

AsyncTasks にはすべて、JSON を読み取るための InputStreams と BufferedReaders がありますがclose()、Streamers と Readers でメソッドを呼び出すことはありません。これはそれでしょうか、それとも AsyncTask は何があっても終了後に収集されますか?

それが問題なら、アプリで 5 つ以上の AsyncTask を実行できないのはなぜですか?

賞金をかけたので、これをより明確に説明します

すべてが彼らのAsyncTasks方法を通過します。それらはすべて、異なるBasicNameValuePairs. コードに簡単な間違いがないことは 100% 確信しています。

AsyncTasks の 1 つの例を次に示します。

private class RunningEvent extends AsyncTask<Void, Void, Response> {

    @Override
    protected void onPreExecute() {
        if (Constants.isOnline(getApplicationContext())) {
            super.onPreExecute();
        } else {
            Toast.makeText(getApplicationContext(),
                    "No internet connection", Toast.LENGTH_LONG).show();
            return;
        }
    }

    @Override
    protected Response doInBackground(Void... empty) {
        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(URL);

        try {
            List<NameValuePair> values = new ArrayList<NameValuePair>(5);
            values.add(new BasicNameValuePair("tag", "eventRunning"));
            values.add(new BasicNameValuePair("userid", String
                    .valueOf(response.user.userid)));
            post.setEntity(new UrlEncodedFormEntity(values));

            HttpResponse httpresponse = client.execute(post);
            HttpEntity entity = httpresponse.getEntity();
            InputStream stream = entity.getContent();

            Log.i("MenuActivity",
                    "Input streamed, parsing Gson for existing events");
            Gson gson = new Gson();
            Reader reader = new InputStreamReader(stream);

            eventresponse = gson.fromJson(reader, Response.class);
            return eventresponse;
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("RunningEvent", "Error sending data to Server");
        }
        return null;
    }

    @Override
    protected void onPostExecute(Response result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        Log.i("MenuActivity", "Binding button");
        if (eventresponse != null) {
            if (eventresponse.success == 1) {
                eventresponse.user = response.user;
                bActivity.setOnClickListener(new OnClickListener() {

                    public void onClick(View arg0) {
                        Intent i = new Intent("com.xxx.xxx.EVENT");
                        i.putExtra("response", eventresponse);
                        running = false;
                        switcher.cancel(true);
                        MenuActivity.this.finish();
                        startActivity(i);
                    }

                });
            } else {
                bActivity.setText("Nieuw activity");
                bActivity.setOnClickListener(new OnClickListener() {

                    public void onClick(View arg0) {
                        Intent i = new Intent("com.xxx.xxx.NEWEVENT");
                        i.putExtra("response", response);
                        running = false;
                        switcher.cancel(true);
                        MenuActivity.this.finish();
                        startActivity(i);
                    }

                });
            }
        } else {
            Log.i("RunningEvent", "Response is null");
        }
    }

}

上記の例は、6 番目として実行されるAsyncTaskことがあり、メソッドに入ることはありませんdoInBackground()。これが の 5Threadの限界だと思いますSERIAL_EXECUTORAsyncTasksほとんどを に入れることで問題を「修正」しましTHREAD_POOL_EXECUTORたが、これはそれを回避しているだけです。

AsyncTasksこれらが実行を停止せず、詰まる理由は何Executorでしょうか?

4

1 に答える 1

8

android.os.AsyncTaskには 2 つの組み込みのエグゼキューターが付属しています。SERIAL_EXECUTOR を使用している場合、スレッドプールはなく、すべての AsyncTask が一度に 1 つずつ順番に実行されます。THREAD_POOL_EXECUTOR を使用している場合 (これが質問で言及されていると思います)、これにより、最大 128 個の AsyncTask を並行して実行できます。

あなたが参照してデバッグから見る数字 5 は、基になるスレッドプール (AKA. THREAD_POOL_EXECUTOR) の corePoolSize であり、 maximumPoolSize とは異なります。AsyncTask ソース コードを調べて、スレッドプールがどのように実装されているかを確認してください。

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;

... ...

/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

ThreadPoolExecutor APIを調べて、このコンストラクターを呼び出すことによって作成されるデフォルトのスレッドプールの動作を確認してください。一般に、corePoolSize は、allowCoreThreadTimeOut が設定されていない限り、たとえアイドル状態であっても、プールに保持するスレッドの数です

デバッグで表示される 5 つの AsyncTask は、実際にはコア スレッド上にあり、終了してアイドル状態になりますが、終了することはありません。 ThreadPoolExecutor.allowCoreThreadTimeOut(boolean)を呼び出すことで、この動作を変更できます。


SERIAL_EXECUTOR の詳細

SERIAL_EXECUTOR はスレッドプールを使用しないと言いましたが、これは正しくありません。SERIAL_EXECUTOR は確かに実際の作業を THREAD_POOL_EXECUTOR に委任しますが、ArrayDeque を使用して次のタスクの送信を制御します (次のタスクは前のタスクが終了した場合に送信されます)。ソースを確認してください。

private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

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

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

したがって、SERIAL_EXECUTOR または THREAD_POOL_EXECUTOR のいずれを使用しても、終了してアイドル状態になっても、スレッドプールには常に 5 つのコア スレッドが表示されます。ただし、コア スレッドの数 (corePoolSize で構成) は、スレッドプールで現在実行されているスレッドの数 (maximumPoolSize で構成) ではありません。

于 2012-09-01T23:56:57.947 に答える