Serviceのライフサイクルの動作確認
ググればライフサイクルのフローチャートが出てくるだけど、念のため動作確認してみた。想定していたのと違う挙動をしたパターンがいくつかあった。
要点
unbind()せずにServiceは停止できない。
テストコード
基本的にはAIDLを使ったServiceを作ってるだけ。テスト内容に合わせてコメントアウトしたり。
ITestService.aidl
package local.ServiceLifecycle; interface ITestService { int add(int x, int y); }
TestService.java
ログ取ってるだけですね。
package local.ServiceLifecycle; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; public class TestService extends Service { private ITestService.Stub binder = new ITestService.Stub() { public int add(int x, int y) throws RemoteException { return x + y; } }; @Override public void onCreate() { Log.i("ServiceLifecycle", "onCreate"); super.onCreate(); } @Override public void onStart(Intent intent, int startId) { Log.i("ServiceLifecycle", "onStart"); super.onStart(intent, startId); } @Override public IBinder onBind(Intent arg0) { Log.i("ServiceLifecycle", "onBind"); return binder; } @Override public boolean onUnbind(Intent intent) { Log.i("ServiceLifecycle", "onUnbind"); super.onUnbind(intent); return true; } @Override public void onRebind(Intent intent) { Log.i("ServiceLifecycle", "onRebind"); super.onRebind(intent); } @Override public void onDestroy() { Log.i("ServiceLifecycle", "onDestroy"); super.onDestroy(); } }
MainActivity.java
こちらもServiceを起動/終了とログ取りだけ。
package local.ServiceLifecycle; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Intent intent; private ITestService binder; private ServiceConnection conn = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { Log.i("ServiceLifecycle", "onServiceConnected"); binder = ITestService.Stub.asInterface(service); } public void onServiceDisconnected(ComponentName name) { Log.i("ServiceLifecycle", "onServiceDisconnected"); } }; @Override public void onCreate(Bundle savedInstanceState) { Log.i("ServiceLifecycle", "Main onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.main); Button btn = (Button)findViewById(R.id.Button01); btn.setOnClickListener(new OnClickListener() { public void onClick(View v) { unbindService(conn); bindService(intent, conn, Context.BIND_AUTO_CREATE); } }); intent = new Intent(this, TestService.class); } @Override protected void onStart() { Log.i("ServiceLifecycle", "Main onStart"); startService(intent); bindService(intent, conn, BIND_AUTO_CREATE); super.onStart(); } @Override protected void onStop() { Log.i("ServiceLifecycle", "Main onStop"); unbindService(conn); stopService(intent); super.onStop(); } @Override protected void onDestroy() { Log.i("ServiceLifecycle", "Main onDestroy"); super.onDestroy(); } }
AndroidManifest.xml
<service android:name="TestService"> <intent-filter> <action android:name="local.ServiceLifecycle.ITestService" /> </intent-filter> </service>
結果
普通にstart/stop
- Activity.startService()
- Service.onCreate()
- Service.onStart()
- Activity.stopService()
- Service.onDestroy()
start2回
- Activity.startService()
- Service.onCreate()
- Service.onStart()
- Activity.startService()
- Service.onStart()
- Activity.stopService()
- Service.onDestroy
Service.onStart()が2回呼ばれてる。
普通にbind/unbind、start/stopは使わない
- Activity.bindService()
- Service.onCreate()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.unbindService()
- Service.onUnbind()
- Service.onDestroy()
Service.onStart()が呼ばれずにService.onBind()が呼ばれてる。
ServiceConnection.onServiceDisconnected()が呼ばれてないけど、こいつはServiceが意図せずに死んだ時(深刻なエラー)のみ呼ばれるらしい。Service.stopSelf()した場合ですらコールされない。ServiceConnection | Android Developers
追記:Serviceを別プロセスで動かしたうえで、Serviceのプロセスを殺した場合にServiceConnection.onServiceDisconnected()呼ばれることは確認してます。
普通にbind/unbind、start/stopは使わない、Service.onBind()でnullを返す
- Activity.bindService()
- Service.onCreate()
- Service.onBind()
- Activity.unbindService()
- Service.onUnbind()
- Service.onDestroy()
onBind()の戻り値がnullの場合は、ServiceConnectionのハンドラが呼ばれないようだ。
bindを2回、start/stopは使わない
- Activity.bindService()
- Service.onCreate()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.bindService()
- Activity.unbindService()
- Service.onUnbind()
- Service.onDestroy()
2回目のActivity.bindService()で何も起こらない。多重bindはブロックするようになっているようだ。
一度unbindしてからbindし直す、onUnbindの戻り値はfalse
- Activity.bindService()
- Service.onCreate()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.bindService()
- Activity.unbindService()
- Service.onUnbind()
- Service.onDestroy()
- Activity.bindService()
- Service.onCreate()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.bindService()
- Activity.unbindService()
- Service.onUnbind()
- Service.onDestroy()
同じことが2回繰り返されるだけ。
一度unbindしてからbindし直す、onUnbindの戻り値はtrue
- Activity.bindService()
- Service.onCreate()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.unbindService()
- Service.onUnbind()
- Service.onDestroy()
- Activity.bindService()
- Service.onCreate()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.unbindService()
- Service.onUnbind()
- Service.onDestroy()
onUnbindの戻り値がfalseの時と挙動変わらず。Service.onDestroy()が走ってしまっているので、わからないでもない。
startしてからbind/unbind
- Activity.startService()
- Service.onCreate()
- Activity.bindService()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.unbindService()
- Service.onUnbind()
- Activity.stopService()
- Service.onDestroy()
startしてからbind/unbindすると、unbindしてもonDestroyは呼ばれない。
startしてからbind/unbindを2度繰り返す、onUnbindの戻り値はtrue
- Activity.startService()
- Service.onCreate()
- Activity.bindService()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.bindService()
- Service.onRebind()
- Activity.unbindService()
- Service.onUnbind()
- Activity.stopService()
- Service.onDestroy()
2回目のbindでService.onRebind()が呼ばれてる。
startしてからbindし、unbindせずにstop
- Activity.startService()
- Service.onCreate()
- Activity.bindService()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Activity.stopService()
unbindせずにstopはできないらしい。
bindしてから1秒後にServiceの方でstop
Service.onBind()にこんなの追加して、1秒後にstopSelf()が呼ばれるように。
AsyncTask<Object, Integer, Object> task = new AsyncTask<Object, Integer, Object>() { @Override protected Object doInBackground(Object... params) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Object result) { Log.i("ServiceLifecycle", "stopSelf"); stopSelf(); } }; task.execute(null);
- Activity.startService()
- Service.onCreate()
- Activity.bindService()
- Service.onBind()
- ServiceConnection.onServiceConnected()
- Service.stopSelf()
やはりunbindせずにstopはできないらしい。