ServiceのBind
ServiceはBindすることで、特定のActivityやサービスに依存させることが出来る。
BindしたサービスはUnbindすると、自動的に破棄される。
BindしたサービスはUnbindすると、自動的に破棄される。
ActivityとServiceの間でやりとりするにはBindする必要があるが、
Unbindすると自動で破棄されてしまうため、BackボタンでHomeに戻るとServiceが意図せず終了してしまい困った。
(HomeボタンならOKなのだが、BackボタンではNGというのはいただけない)
Unbindすると自動で破棄されてしまうため、BackボタンでHomeに戻るとServiceが意図せず終了してしまい困った。
(HomeボタンならOKなのだが、BackボタンではNGというのはいただけない)
Serviceのライフサイクル
Serviceには2つの異なるライフサイクルがある。
1つは、Startに始まり、Stopに終わるパターン。Stopは外からIntentによりStopする場合と、Service自身がStopSelfする場合と、2つの方法がある。
もう1つは、Bindに始まり、Unbindに終わるパターン。
もう1つは、Bindに始まり、Unbindに終わるパターン。
説明すると長くなるので、詳しくは本家をどうぞ
http://developer.android.com/guide/components/services.html
http://developer.android.com/guide/components/services.html
ServiceのStartとBindの合せ技
Serviceのライフサイクルが複雑になるので推奨はしない。
ServiceをStartさせることで、BindしUnbindしてもServiceが破棄されないように小細工できる。
ただしStartさせたサービスは、外からStopするか、Service自身にStopSelfさせる必要がある。
そのためUnbindされると、StopSelfのフラグをONにし、Serviceが特定の状態になったらStopSelfが実行されるようにした。
さらにRebindされると、StopSelfのフラグをOFFにする。
ただしStartさせたサービスは、外からStopするか、Service自身にStopSelfさせる必要がある。
そのためUnbindされると、StopSelfのフラグをONにし、Serviceが特定の状態になったらStopSelfが実行されるようにした。
さらにRebindされると、StopSelfのフラグをOFFにする。
実際にやってみたが、動作が不安定でリリースするアプリには載せられない。
その後、いろいろ試してみて、安定して使える動作になった。
ポイントは
その後、いろいろ試してみて、安定して使える動作になった。
ポイントは
- ライフサイクルを出来る限り短く。
- 変化する状態は少なく
- bindはごく短時間で終わらせる。Connectedが呼ばれたら、その中でUnbindしてしまう作りにした。
サンプル
Activityの定義、抜粋。
public class MainActivity extends Activity
implements MyService.Listner {
onCreateでstartServiceとbindServiceをコール。startServiceを呼ばずにbindService単独でAUTO_CREATEを付けてServiceを起動させるとと、Unbindで死んでしまう。
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Intent intent = new Intent(this, MyService.class);
intent.putExtra(MyService.KEY_COMMAND, MySerVice.COMMAND.HELLO);
startService(intent);
bindService(intent, mMyServiceConnection , 0);
}
リスナーを渡したらすぐさまUnbind。
ServiceConnection mMyServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v(TAG, "Service connected");
TimerService timerService = ((MyService.MyServiceBinder)service).getTimerService();
timerService.setListner(MainActivity.this);
unbindService(mTimerServiceConnection);
}
public void onServiceDisconnected(ComponentName name) {
Log.v(TAG, "Service disconnected");
}
};
stopServiceではなくstartServiceでServiceを終了させる。Serviceの状態によっては、すぐに終了せず、時間を置いてから自滅させたかったのでこうした。
public void onDestroy() {
super.onDestroy();
Intent intent = new Intent(this, TimerService.class);
intent.putExtra(TimerService.KEY_COMMAND, TimerService.COMMANDS.BYE);
startService(intent);
}
Serviceの定義、抜粋。
public interface TimerListner {
void onServiceStarted(CharSequence message);
}
onStartCommandでExtraを取りだし、Activityでセットされた値に応じて処理を変える
@Override
public int onStartCommand(Intent intent, int flags, int id) {
Log.v(TAG, "onStartCommand");
COMMANDS command = (COMMANDS)intent.getSerializableExtra(KEY_COMMAND);
switch(command) {
case BYE:
killTimer = new Timer();
...
...
public void run() {
stopSelf();
}
...
...
break;
default:
break;
}
if (mListner != null)
mListner.onServiceStarted("hello");
return START_STICKY;
}
public void onDestory() {
if (killerTimer != null)
killerTimer.cancel();
}
UnbindではTRUEを返す。そうしないと再Bind時に、RebindもBindも呼ばれないことがある。APIレベルに依るのか?
@Override
public IBinder onBind(Intent intent) {
Log.v(TAG, "onBind");
return mBinder;
}
@Override
public void onRebind(Intent intent) {
Log.v(TAG, "onRebind");
return;
}
@Override
public boolean onUnbind(Intent intent) {
Log.v(TAG, "onUnbind");
return true;
}
vs


