Android のサービスは、startService
で「開始状態」、bindService
で「接続状態」となり、サービスを停止させる stopService
は、unbindService
で接続を解除してから実行しないと止まらない、とドキュメントに書いてあります。
Managing the Lifecycle of a Service | Android Developers より
In cases like this, stopService() or stopSelf() does not actually stop the service until all clients unbind.
それから、一見、サービスが切断された時に呼び出されるように見える [ServiceConnection.onServiceDisconnected
](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceDisconnected(android.content.ComponentName) は、
onServiceDisconnected()
The Android system calls this when the connection to the service is unexpectedly lost, such as when the service has crashed or has been killed. This is not called when the client unbinds.
とあるように、実はサービスが異常終了した時などしか呼ばれないとのことです。
今回、偶然にも、
ServiceConnection.onServiceDisconnected
が呼ばれるという動きをするサービスができたので、備忘録として残しておきます。
条件は、startService した後、bindService の第2引数を Context.BIND_AUTO_CREATE
ではなく 0
にすること。
//StartService.java
Intent intent = new Intent(context, TestService.class);
final ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("ServiceTest", "onServiceConnected");
binder = ITestService.Stub.asInterface(service);
}
// stopService すると呼ばれる
public void onServiceDisconnected(ComponentName name) {
Log.i("ServiceTest", "onServiceDisconnected");
context.unbindService(conn); // これ呼ばないとリークする
}
};
// サービス開始&接続
context.startService(intent);
context.bindService(intent, conn, 0); // not BIND_AUTO_CREATE
// ボタンを押したらサービス停止
findViewById(R.id.btnCallTerminate)
.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
context.stopService(intent);
}
});
サービス側のコードは省略してしまったけど、stopService すると、
の順で呼ばれてます。onServiceDisconnected で context.unbindService
を呼ばないと、アプリ終了時にメモリリークが検出されます。また、呼ばなくても、2. 3. は変わりません。
外から stopService でなく、サービス内から stopSelf
でも同じでした。
接続中にサービスを停止しても、onServiceDisconnected で補足できるので、自然と言えば自然ですが、説明と違う動きをされると混乱しますね。(どこかに書いてあるのかな?)