2012-08-28 7 views
27

私は2つのASyncTaskを持っています.1つはhttpPostから値を取得し、もう1つはUIの一部の要素(リストビューを含む)を更新します。 問題は、両方のASyncTaskが同じバックグラウンドスレッドを共有しているためです。ネットワークの開始が最初に開始され、遅い(ネットワーク接続不良のため)。他のバックグラウンドスレッドは、無責任なアプリにするには時間がかかりすぎます。他のユーザーをブロックするASyncTasks

両方のASyncTasksは独立しているので、他のものを待つためにはかなり愚かなものです。より論理的なasynctasks別のクラスは異なるスレッドを使用する、私は間違っている?

ASyncTask文書を読む。 executeOnExecutor()の使用に関する話ですが、11より低いAPIレベルでどうすれば解決できますか?ここで

は "問題" で

 new Task1().execute(); 
     new Task2().execute(); 

を再現する小さな例を行く

public class Task1 extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected Void doInBackground(Void... params) { 
     GLog.e("doInBackground start 1"); 
     SystemClock.sleep(9000); 
     GLog.e("doInBackground end 1"); 
     return null; 
    } 

    @Override 
    protected void onPreExecute() { 
     GLog.e("onPreExecute 1"); 
     super.onPreExecute(); 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     GLog.e("onPostExecute 1"); 
     super.onPostExecute(result); 
    } 

} 

public class Task2 extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected void onPreExecute() { 
     GLog.e("onPreExecute 2"); 
     super.onPreExecute(); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     GLog.e("doInBackground start 2"); 
     SystemClock.sleep(9000); 
     GLog.e("doInBackground end 2"); 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     GLog.e("onPostExecute 2"); 
     super.onPostExecute(result); 
    } 

} 
+0

なぜUIを更新するAsyncTaskがありますか?あなたは、Iiスレッドで同期させる必要があります。あなたのUI AsyncTaskはバックグラウンドスレッド上で何か他のことをしますか? –

+0

私はそれをニュースのリストビューを表示するために使用します。 onPreExecuteでは、loading()UIを表示し、バックグラウンドでインターネットからニュースを取得し、onPostExecuteでアダプタをlistviewに割り当てます。そのアプローチは間違っていますか? – Addev

+0

@Addev:なぜ最初の 'onPostExecute(...)'メソッドで2番目の 'AsyncTask'を起動しないのですか?必要なのは、一方のAsyncTaskが他のAsyncTaskの結果に依存していることです。その場合、事実上同期要件があり、2つの非同期操作を並行して実行するべきではありません。 – Squonk

答えて

46

これは私が私のコードでこれを処理する方法である:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 
    new MyAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
} else { 
    new MyAsyncTask().execute(); 
} 

そしてMyAsyncTaskを置き換えますあなたのものはそれぞれTask1Task2です。基本的には、Honeycombに登場しているAsyncTaskの変更(Android SDKのドキュメントhereの「実行の順序」のセクションを参照)。その前にHCと上級者向けに起動します。新しい動作が気に入らなければexecuteOnExecutor()を使用してください。私は)考えて

7

Aこれを行うには、もう少し一般的な方法は、そのようなユーティリティクラスで2つのヘルパー・メソッドを置くことです:

class Utils { 

    @SuppressLint("NewApi") 
    public static <P, T extends AsyncTask<P, ?, ?>> void execute(T task, P... params) { 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 
      task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); 
     } else { 
      task.execute(params); 
     } 
    } 
} 

次にあなたがUtils.execute(mytask)Utils.execute(mytask, params)でタスクを実行することができ、それはの世話をしますそれらを並行して実行する。

+0

ありがとうございます。後継のため、 'AsyncTask.execute()'をオーバーライドしようとしないでください - できません。それは「最終」です。 – TalkLittle

+0

また、最初のメソッドは不要で、実際には予期しない動作が発生する可能性があります( 'params'は空の配列ではなく' null')。それを削除すると、Honeycombの前のデバイスでコンパイル/正常に実行されます。 – TalkLittle

+0

それは不要ではなく、それは入力を保存します:) –

0

すべてのAsyncTaskは、APIにコード化された同じThreadPoolExecutorで実行されるという問題があります。このThreadPoolExecutorはあなたのAndroidのバージョンに応じて異なる数のWorkerThreadを作成できます。ナンバーバージョンは覚えていないが、古いAndroidバージョンでは1つのWorkerThreadだったという考えがある。その後、それ以降のバージョンでは5に更新されました。そして最近、再び1に戻った。これがAsyncTasksがブロックされている理由です。それらはすべて同じWorkerThread上で実行され、したがってそれらは順番に実行されます。真の並列実行を実現するには、executeOnExecutorをTHREAD_POOL_EXECUTORで試してみてください。ただし、API 11以降でのみ使用できます。