Serviceを使う(1) LocalServiceによる常駐型アプリ
Androidで常駐型アプリケーションを作成する場合に便利なServiceについてライフサイクル・使い方を解説します。サービスの利用例はステータス通知(Notification)を変化させる等をご確認ください。Serviceを使う(1)では簡単化のため、Remote Messenger Serviceを次回以降として、LocalServiceに特化して解説します。
- Serviceのライフサイクル
- onCreate / onStartCommand / onDestroyの3つの状態遷移
- サービスの実行方法によってライフサイクルが異なる
- サービスの実行方法はContext#startServiceとContext#bindServiceの2種類
- startService/stopService
- Service全般として実行中はServiceからActivityへIntentの発行が可能
- サービス起動後はActivityからServiceを制御する経路がない
- Serviceの生存期間はActivityに依存しない。明示的にstopServiceが呼ばれるまで動き続ける。
- bindService/unbindService
- バインド(bind)という仕組みを使い、ActvitiyとServiceでコネクションを確立する(接続する)
- バインドを使うことでActivityからServiceを制御できる
- Serviceの生存期間はコネクションに依存。コネクションが切断されるとServiceは終了する。
サンプルコード、詳細は以下から。はじめに一般的なサービスのライフサイクル、startServiceによるサービス起動を紹介します。バインドのサンプルコードは記事後半になるので、適宜読み飛ばしてください。
サービスのライフサイクル

Context#startServiceによる実行の場合、サービスのライフサイクルはonCreate / onStartCommand / onDestroy の3つのコールバックメソッドが呼ばれます。
- public void onCreate()
- public void onDestroy()
- public int onStartCommand(Intent intent, int flags, int startId)
onCreateはサービスのインスタンス生成時(複数回startServiceを実行した場合、初回のみ)呼び出されます。onStartCommandメソッドではstartServiceで送られたIntentを受けとります。
stopServiceメソッドによるサービス終了のタイミングでonDestroyが呼ばれます。ActivityでstopServiceを呼ばず、アプリケーションを終了した場合はServiceは終了せず、バックグラウンドで動き続けます。
※IntentはIntentを使って画面を遷移する(明示的Intent)を参照してください。
サンプルコード
サンプルとして以下の画像のようにServiceを実行するボタンを持つActivityを準備します

サービスの実装
MyService.java
public class MyService extends Service {
static final String TAG="LocalService";
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
Toast.makeText(this, "MyService#onCreate", Toast.LENGTH_SHORT).show();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand Received start id " + startId + ": " + intent);
Toast.makeText(this, "MyService#onStartCommand", Toast.LENGTH_SHORT).show();
// 強制終了時、システムによる再起動を求める場合はSTART_STICKYを利用
// 再起動が不要な場合はSTART_NOT_STICKYを利用する
return START_STICKY;
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
Toast.makeText(this, "MyService#onDestroy", Toast.LENGTH_SHORT).show();
}
}
6,12,20行目:コールバックメソッドのみ実装した簡単なServiceです。サービスを使う際は、AndroidManifestに記述を追加する必要があります。
AndroidManifest.xml
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name="ServiceControllerActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="MyService" />
</application>
サービスを起動するActivityの実装
ServiceControllerActivity.java
public class ServiceControllerActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.StartButton);
btn.setOnClickListener(btnListener);//リスナの登録
btn = (Button) findViewById(R.id.StopButton);
btn.setOnClickListener(btnListener);//リスナの登録
}
private OnClickListener btnListener = new OnClickListener() {
public void onClick(View v) {
switch(v.getId()){
case R.id.StartButton://startServiceでサービスを起動
startService(new Intent(ServiceControllerActivity.this, MyService.class));
break;
case R.id.StopButton://stopServiceでサービスの終了
stopService(new Intent(ServiceControllerActivity.this, MyService.class));
break;
}
}
};
13行目から始まるOnClickListener(ボタンが押下されたときに呼び出される)でサービスの起動/終了を行っています。
19行目、22行目でIntent(Context, Class)の形でIntentを生成してstartService/stopServiceの引数にして、サービス(ここではMyService)を呼び出します。
StartButton、StopButtonの順番で押下した際のログでライフサイクルを確認してみます。

Logcat
02-15 06:45:10.280: INFO/LocalService(1619): onCreate
02-15 06:45:10.290: INFO/LocalService(1619): onStartCommand Received start id 1: Intent { cmp=org.jpn.techbooster.sample.serviceActivity/.MyService }
02-15 06:45:18.170: INFO/LocalService(1619): onDestroy
StartButton、StartButton、StopButtonの順番で押下すると、onCreateメソッドの呼び出しが初回のみであることがわかります。
Logcat
02-15 06:45:19.530: INFO/LocalService(1619): onCreate
02-15 06:45:19.540: INFO/LocalService(1619): onStartCommand Received start id 1: Intent { cmp=org.jpn.techbooster.sample.serviceActivity/.MyService }
02-15 06:45:20.170: INFO/LocalService(1619): onStartCommand Received start id 2: Intent { cmp=org.jpn.techbooster.sample.serviceActivity/.MyService }
02-15 06:45:22.080: INFO/LocalService(1619): onDestroy
バインド利用時のサービスのライフサイクル
![]() |
![]() |
| バインド利用時のライフサイクル | startService利用時のライフサイクル |
バインド(bind)という仕組みを使い、ActvitiyとServiceを接続するケースでは、ライフサイクルが多少異なります。図にある通り、onStartCommandメソッドが呼び出されることがありません。
通常のonCreate/onDestroyに加えて、バインド時は以下のコールバックメソッドを利用します。
- public abstract IBinder onBind (Intent intent)
- public boolean onUnbind (Intent intent)
- public void onRebind (Intent intent)
onBindはバインド(接続時)、Unbindはバインド解除(切断時)に呼び出されます。onRebindメソッドは図中には現れませんが、Unbind後に再接続する場合、onRebindメソッドを利用することができます。使う際はonUnbind メソッドの返り値をtrueに設定します。
サンプルコード
図のActivitiy下2つのボタン部分とServiceにバインドを実装します。

バインドの実装
MyService.java
public class MyService extends Service {
// onCreate , onStartCommand , onDestroy() はstartServiceと同じなので省略
/*
* 以下はBind時に必要なコード
* */
//サービスに接続するためのBinder
public class MyServiceLocalBinder extends Binder {
//サービスの取得
MyService getService() {
return MyService.this;
}
}
//Binderの生成
private final IBinder mBinder = new MyServiceLocalBinder();
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(this, "MyService#onBind"+ ": " + intent, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onBind" + ": " + intent);
return mBinder;
}
@Override
public void onRebind(Intent intent){
Toast.makeText(this, "MyService#onRebind"+ ": " + intent, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onRebind" + ": " + intent);
}
@Override
public boolean onUnbind(Intent intent){
Toast.makeText(this, "MyService#onUnbind"+ ": " + intent, Toast.LENGTH_SHORT).show();
Log.i(TAG, "onUnbind" + ": " + intent);
//onUnbindをreturn trueでoverrideすると次回バインド時にonRebildが呼ばれる
return true;
}
}
18行目、25行目、31行目それぞれonBind、onRebind、onUnbindメソッドを実装、Toastを表示します。
サービスを起動するActivityの変更
ボタンのOnClickListenerにbindService/unbindServiceを追加します。
ServiceControllerActivity.java
private OnClickListener btnListener = new OnClickListener() {
public void onClick(View v) {
switch(v.getId()){
case R.id.StartButton://startServiceでサービス起動
startService(new Intent(ServiceControllerActivity.this, MyService.class));
break;
case R.id.StopButton://stopServiceでサービス終了
stopService(new Intent(ServiceControllerActivity.this, MyService.class));
break;
case R.id.BindButton://doBindService
doBindService();
break;
case R.id.UnbindButton://doUnbindService
doUnbindService();
break;
default:
break;
}
}
};
バインドするためのServiceConnectionを実装
バインドするためにはServiceConnectionを使います。Activity側でServiceConnectionと以下のServiceConnectionのメソッドを用意します。
- public void onServiceConnected(ComponentName className, IBinder service)
- public void onServiceDisconnected(ComponentName className)
ServiceConnection#onServiceConnectedメソッドはActivityとServiceのコネクションが確立した際に呼び出されます。
引数のIBinder serviceで、サービスのバインダーを受け取れます。バインダー経由でServiceのインスタンスを取得することが可能、つまりダイレクトにサービス側のメソッド呼び出しができるようになります。
ServiceConnection#onServiceDisconnectedメソッドはプロセスのクラッシュなど意図しないサービスの切断が発生した場合に利用されます(呼び出されること自体、あまり好ましい状況ではないでしょう)。
ServiceControllerActivity.java
//取得したServiceの保存
private MyService mBoundService;
private boolean mIsBound;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// サービスとの接続確立時に呼び出される
Toast.makeText(ServiceControllerActivity.this, "Activity:onServiceConnected",
Toast.LENGTH_SHORT).show();
// サービスにはIBinder経由で#getService()してダイレクトにアクセス可能
mBoundService = ((MyService.MyServiceLocalBinder)service).getService();
//必要であればmBoundServiceを使ってバインドしたサービスへの制御を行う
}
public void onServiceDisconnected(ComponentName className) {
// サービスとの切断(異常系処理)
// プロセスのクラッシュなど意図しないサービスの切断が発生した場合に呼ばれる。
mBoundService = null;
Toast.makeText(ServiceControllerActivity.this, "Activity:onServiceDisconnected",
Toast.LENGTH_SHORT).show();
}
};
void doBindService() {
//サービスとの接続を確立する。明示的にServiceを指定
//(特定のサービスを指定する必要がある。他のアプリケーションから知ることができない = ローカルサービス)
bindService(new Intent(ServiceControllerActivity.this,
MyService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// コネクションの解除
unbindService(mConnection);
mIsBound = false;
}
}
サンプル内、doBindServiceメソッドはサービスにバインド、doUnbindServiceメソッドはサービスをアンバインド(切断)するメソッドです。
BindButton、UnbindButtonの順番で押下した際のログでライフサイクルを確認してみます。

Logcat
02-15 07:25:51.090: INFO/LocalService(1619): onCreate
02-15 07:25:51.110: INFO/LocalService(1619): onBind: Intent { cmp=org.jpn.techbooster.sample.serviceActivity/.MyService }
02-15 07:25:52.890: INFO/LocalService(1619): onUnbind: Intent { cmp=org.jpn.techbooster.sample.serviceActivity/.MyService }
02-15 07:25:52.890: INFO/LocalService(1619): onDestroy