-
Notifications
You must be signed in to change notification settings - Fork 354
2.08. 非同期処理
この章では、Android での非同期処理について解説します。
参考:Services | Android Developers
参考:Loaders | Android Developers
参考:Processes and Threads | Android Developers
-
Service
- [Service の状態](#Service の状態)
- [Service のライフサイクル](#Service のライフサイクル)
- [Service を構築するクラス](#Service を構築するクラス)
- Loader
- AsyncTask
Service とは、バックグラウンドで動作する Android のコンポーネントです。
Service
には、その呼び出し方によって 2 つのいずれかの状態をとります。
Context#startService(Intent)
によって呼び出された時の状態です。
Context#bindService(Intent)
によって呼び出された時の状態です。
Service
がどのように呼び出されたかによって、ライフサイクルが異なります。
Context#startService(Intent)
によって開始されたSerivce
は、自身が終了を宣言するか、誰かが終了を命令するまで生存し続けます。
Context#bindService(Intent)
によってバインドされたService
は、バインドしている呼び出し元が全員バインドの解除を行うまで生存し続けます。
一般的な Service を作成するひな形クラスです。
バックグラウンドで動作するものではありますが、その実動作しているスレッドは、Service を動かしているプロセスのメインスレッドです。
つまり、Service 内でブロックする処理を記述すると、メインスレッドの処理がブロックします。よって、独自のプロセスで動かしたい場合は、その旨 AndroidManifest で宣言する必要があり、また、ブロックする処理を実行する場合は、自分でスレッドを新しく立てる必要があります。
Intent による呼び出しで開始される Service であり、かつ、Service の開始要求を 1 つずつ順に処理するワーカスレッド上で動作する特別な Service です。 一度に複数の処理を並列して行う必要がない場合は、IntentService を利用するほうが実装が簡単です。
非同期に処理を行うための新しいフレームワークです。特に、ネットワークやファイル I/O を介してデータを読み出すためのフレームワークとして設計されているものです。
Activity や Fragment のライフサイクルに合わせて動作するように作られています。
Honeycomb 以後から導入されました。
SupportPackage にも含まれているので、2.x 系の OS でも利用することができます。
非同期処理を行うためのフレームワークとして、後述するAsyncTask
もあります。
Activity
やFragment
のライフサイクルに合わせて動作する点で、データの読み出しにはLoader
が適しています。
ネットワーク通信やその他のファイル I/O などによってデータを読み出す場合は、このクラスを拡張して非同期処理を記述します。
別の章で解説する、データベースからのデータの読み出しに特化したクラスです。
名前の通り、非同期処理のためのクラスです。
非同期に実行したい処理と、処理前、処理後のメインスレッド上での処理を記述するため、このクラスを継承して使います。
AsyncTask
では、内部でスレッドプールを持っています(Donut までは単一のスレッドで動作していた)。
デフォルトでは 5 つのスレッドがプールされており、内部で並列して複数の非同期処理を実行できるようになっています(Honeycomb 以降は、スレッドの並列実行における諸問題を回避するため単一スレッドで動作するように戻っている)。
最大でプールされるスレッド数は 128 です。
AsyncTask
オブジェクトは、使い回しができません。一度処理が完了すると、その後にもう一度非同期処理の実行を依頼した時点で、例外が投げられます。
よって、再度非同期処理を実行したい場合は、新たにAsyncTask
オブジェクトを作成する必要があります。
/**
* 非同期処理を実行するためのネストクラス。
*
* ジェネリクスの仕組みを用いて、非同期処理に渡す引数の型、進捗を監視するコールバック用の型、非同期処理の結果を表す型を指定する。
*
* Activity や Fragment のライフサイクルに合わせて、自分で AsyncTask をコントロールする必要があり、これを行わないと
* 特に {@link AsyncTask#onPostExecute()} で、参照するオブジェクトが既にメモリから破棄されていて NullPointerException となることが起こりえる。
*/
public class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private Context mApplicationContext;
public MyAsyncTask(Context applicationContext) {
super();
mApplicationContext = applicationContext;
}
/**
* 非同期処理を実行する前に UI スレッドで実行する処理を書く
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(mContext, "onPreExecute", Toast.LENGTH_SHORT).show();
}
/**
* 非同期処理の進捗を受け取るコールバック。
*/
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
Toast.makeText(mContext, "onProgressUpdate", Toast.LENGTH_SHORT).show();
}
/**
* 非同期処理の本体
* 引数は非同期処理内容に渡すためのパラメータ配列。
*/
@Override
protected Void doInBackground(Void... params) {
// 2 秒おきに進捗を通知する
try {
publishProgress();
Thread.sleep(2000L);
publishProgress();
Thread.sleep(2000L);
publishProgress();
Thread.sleep(2000L);
publishProgress();
Thread.sleep(2000L);
publishProgress();
Thread.sleep(2000L);
publishProgress();
} catch (InterruptedException e) {
Log.e(MyAsyncTask.class.getSimpleName(), "thread interrupted: ", e);
}
return null;
}
/**
* 非同期処理の実行後に、UI スレッドで実行する処理。
* 引数は {@link AsyncTask#execute(Object...)} の返り値。
*/
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Toast.makeText(mContext, "onPostExecute", Toast.LENGTH_SHORT).show();
}
}
Portions of this page are reproduced from work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.