[Android] AsyncTask:AsyncTaskの実行順序を指定する

ここではAsyncTaskデフォルトの実行順序と実行順序の指定方法ついて説明します。
広 告
目次
前提条件
- 特になし
動作確認端末
- Google Nexus 7 – 5.1.1 – API22(実機)
1. AsyncTaskデフォルトの実行順序
AsyncTaskが導入された当初は、AsyncTask#execute(Params…)を実行すると単一のバックグラウンドスレッドで複数のタスクが順番通りに実行されていました。
Android1.6からは、スレッドプールを使って複数のタスクが並列で動作するような挙動に変更されました。
Android3.0以降では、複数タスクの並列実行が原因で発生するアプリケーションエラーを回避するために、単一のバックグランドスレッドで複数のタスクが順番どおりに実行する挙動に戻りました。
以下のコードを見てください。AsyncTaskを5つ同時に実行するコードになります。実行順序がわかるようにはLogcat出力処理を入れています。
デフォルトの実行順序を確認するコード
import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.net.MalformedURLException; import java.net.URL; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final URL[] urls; try { urls = new URL[]{ new URL("https://www.google.com"), new URL("https://www.google.com"), new URL("https://www.google.com"), new URL("https://www.google.com"), new URL("https://www.google.com") }; } catch (MalformedURLException e) { finish(); return; } new DownloadTask("download1").execute(urls); new DownloadTask("download2").execute(urls); new DownloadTask("download3").execute(urls); new DownloadTask("download4").execute(urls); new DownloadTask("download5").execute(urls); } private final class DownloadTask extends AsyncTask<URL, Integer, Long> { /** スレッド名 */ private final String mThreadName; public DownloadTask(String threadName) { mThreadName = threadName; } @Override protected Long doInBackground(URL... urls) { // スレッド名を設定(動作確認用) Thread.currentThread().setName(mThreadName); // 受け取ったURLの数 final int count = urls.length; // ファイルのダウンロード合計サイズ long totalSize = 0; for (int i = 0; i < count; i++) { try { // ファイルのダウンロード処理を時間がかかると仮定 Log.i(Thread.currentThread().getName(), "download count " + i); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } totalSize++; } return totalSize; } } }
上記コードをGoogle Nexus 7(Android5.1.1)で実行すると下記のとおり順番通りでLogcatに出力されます。
Google Nexus 7(Android5.1.1)で実行した時のLogcat出力内容
I/download1: download count 0 I/download1: download count 1 I/download1: download count 2 I/download1: download count 3 I/download1: download count 4 I/download2: download count 0 I/download2: download count 1 I/download2: download count 2 I/download2: download count 3 I/download2: download count 4 I/download3: download count 0 I/download3: download count 1 I/download3: download count 2 I/download3: download count 3 I/download3: download count 4 I/download4: download count 0 I/download4: download count 1 I/download4: download count 2 I/download4: download count 3 I/download4: download count 4 I/download5: download count 0 I/download5: download count 1 I/download5: download count 2 I/download5: download count 3 I/download5: download count 4
上記の通り、Android5.1.1では「単一のバックグラウンドスレッドで複数のタスクが順番通り実行される挙動」をとっていることが確認できます。
2. 実行順序を指定する方法
AsyncTaskの実行順序を指定するためには、AsyncTask#executeOnExecutor (Executor exec, Params… params)を使います。「スレッドプールを使って複数のタスクが並列で動作するような挙動」に変更したい場合は、第一引数にAsyncTask.THREAD_POOL_EXECUTORを指定することで実現できます。
executeOnExecutor((AsyncTask.THREAD_POOL_EXECUTOR)の挙動を確認するコード
import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.net.MalformedURLException; import java.net.URL; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final URL[] urls; try { urls = new URL[]{ new URL("https://www.google.com"), new URL("https://www.google.com"), new URL("https://www.google.com"), new URL("https://www.google.com"), new URL("https://www.google.com") }; } catch (MalformedURLException e) { finish(); return; } new DownloadTask("download1").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urls); new DownloadTask("download2").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urls); new DownloadTask("download3").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urls); new DownloadTask("download4").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urls); new DownloadTask("download5").executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urls); } private final class DownloadTask extends AsyncTask<URL, Integer, Long> { /** スレッド名 */ private final String mThreadName; public DownloadTask(String threadName) { mThreadName = threadName; } @Override protected Long doInBackground(URL... urls) { // スレッド名を設定(動作確認用) Thread.currentThread().setName(mThreadName); // 受け取ったURLの数 final int count = urls.length; // ファイルのダウンロード合計サイズ long totalSize = 0; for (int i = 0; i < count; i++) { try { // ファイルのダウンロード処理を時間がかかると仮定 Log.i(Thread.currentThread().getName(), "download count " + i); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } totalSize++; } return totalSize; } } }
上記コードをGoogle Nexus 7(Android5.1.1)で実行すると下記のとおり順番通りでLogcatに出力されます。
Google Nexus 7(Android5.1.1)で実行した時のLogcat出力内容
I/download1: download count 0 I/download2: download count 0 I/download3: download count 0 I/download4: download count 0 I/download5: download count 0 I/download3: download count 1 I/download5: download count 1 I/download4: download count 1 I/download2: download count 1 I/download1: download count 1 I/download5: download count 2 I/download4: download count 2 I/download2: download count 2 I/download3: download count 2 I/download1: download count 2 I/download1: download count 3 I/download2: download count 3 I/download4: download count 3 I/download5: download count 3 I/download3: download count 3 I/download1: download count 4 I/download2: download count 4 I/download5: download count 4 I/download3: download count 4 I/download4: download count 4
3. 参考URL
AsyncTask | Android Developer
http://developer.android.com/intl/ja/reference/android/os/AsyncTask.html