前回に引き続き、今回もサービス(Service)に関する記事です。
Serviceは常駐型のアプリケーションを作る時に使うバックグラウンド処理をしてくれる奴です。
今回はバインド(bind)という仕組みを使ってやり方を紹介してみます(^ω^)
バインド(Bind)を利用したサービス
前回(【Android】サービス(Service)を使ってバックグラウンド処理をする(1))前回のstartService、stopServiceで利用するサービスの場合、
一度サービスを動かした場合、呼び出し元からは制御ができません、stopServiceで止めるくらいです。
加えて、呼び出し元が終了した場合でもサービスは動き続けます。
バインド(Bind)という仕組みを利用したサービスの場合、
呼び出し時に接続を行い、呼び出し元のActivityから関数を呼び出したり制御ができます。
また、呼び出し元が終了した場合、接続が切れサービスも一緒に終了してくれます、
バインド(束縛)をしているので一緒に引きずられて落ちるようなイメージですね
ライフサイクルが違ったり、内部クラスを使ったりとこっちのほうは若干メンドクサイです(´・ω・`)
AndroidManifest.xmlにServiceを追加
忘れずに追加です。
これから作るサービスのクラス名と同じにしておきます。
今回は TestBindService としました。
</activity> <service android:name="TestBindService" /> </application> </manifest>
Serviceクラスの派生クラスを作成する
クラスファイルを追加してServiceクラスの派生クラスを作成します。
ライフサイクルは以下のような感じ。
onCreateとonDestroyはバインドを利用しない場合と同じですね。
onStartCommandの代わりに、
- onBind
- onUnbind
- ServiceConnectionクラスのonServiceConnected
【実装例】
・TestBindeSerive.java
public class TestBindService extends Service { // Binderクラスを継承した内部クラス public class BindServiceBinder extends Binder{ TestBindService getService(){ return TestBindService.this; } } // Binderの作成 private final IBinder mBinder = new BindServiceBinder(); @Override public void onCreate() { } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public boolean onUnbind(Intent intent){ return true; } @Override public void onDestroy(){ } }
Binderクラスを継承した内部クラスBindServiceBinderが定義されています。
このクラスではTestBindService自身を返す関数だけ持っています。
次に、BindServiceBinderをインスタンスを生成。
onBindメソッドの返り値でそれを渡しています。
「あれ?ライフサイクルの中にあるonServiceConnectedはどこ?」
と思われる方もいるかもしれませんが、
その部分はサービスの起動側に書きます、ややこしい(´ω`)
Activityからサービスの起動をする
今度は呼び出し元のActivityです。
前回はstartServiceで開始、stopServiceで終了だったのに対し、
今回は
- bindService
- unbindService
両方の関数の引数には以下の2つの関数を持つ、
ServiceConnectionインターフェイスを実装したクラスのインスタンスを渡します。
- onServiceConnectedメソッド
- onServiceDisconnectedメソッド
名前を見てなんとなくわかると思いますが、接続が成功するとonServiceConnectedメソッドが呼び出されます。
このメソッドの引数には先ほどTestBindeSeriveクラスで作成したBinderが渡されるので、
getServiceメソッドでサービスのインスタンスが取得できます。
サンプルプログラム
■GitHub
ouka-tenshi/Android-Sample/tree/master/ServicBindSample
サービスを呼び出して各メソッド内ログを吐き出します。
適当な関数をサービス側に作成して、Activity側のボタンを押して呼び出します。
・MainActivity
public class MainActivity extends Activity { private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT; // レイアウト LinearLayout ll; Button btnBind; Button btnUnBind; Button btnFunc; // Service TestBindService mService; boolean connectionStatus; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i("MainActivity", "onCreate"); ll = new LinearLayout(this); ll.setGravity( Gravity.CENTER_VERTICAL); ll.setOrientation( LinearLayout.VERTICAL ); btnBind = new Button(this); btnUnBind = new Button(this); btnFunc = new Button(this); btnBind.setOnClickListener( new ServiceOnClickListener() ); btnUnBind.setOnClickListener( new ServiceOnClickListener() ); btnFunc.setOnClickListener( new ServiceOnClickListener() ); btnBind.setText("Service Onbind"); btnUnBind.setText("Service Unbind"); btnFunc.setText("Service 適当な関数"); ll.addView( btnBind , WC ); ll.addView( btnUnBind, WC ); ll.addView( btnFunc , WC ); setContentView(ll); } // コネクション作成 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // サービス接続時に呼ばれる Log.i("ServiceConnection", "onServiceConnected"); // BinderからServiceのインスタンスを取得 mService = ((TestBindService.BindServiceBinder)service).getService(); } @Override public void onServiceDisconnected(ComponentName arg0) { // サービス切断時に呼ばれる Log.i("ServiceConnection", "onServiceDisconnected"); mService = null; } }; // リスナー class ServiceOnClickListener implements OnClickListener{ @Override public void onClick(View view) { if( view == btnBind ){ // バインド開始 bindService( new Intent( MainActivity.this, TestBindService.class ) , connection, Context.BIND_AUTO_CREATE ); connectionStatus = true; }else if( view == btnUnBind ){ if( connectionStatus ){ // バインドされている場合、バインドを解除 unbindService( connection ); connectionStatus = false; } }else if( view == btnFunc ){ if( connectionStatus ){ // 適当な関数を呼び出し mService.TestFunction(); } } } } }
・TestBindService
public class TestBindService extends Service { public class BindServiceBinder extends Binder{ // TestBindService自身を返す TestBindService getService(){ return TestBindService.this; } } // Binderの作成 private final IBinder mBinder = new BindServiceBinder(); @Override public void onCreate() { Log.i("BindService", "onCreate"); } @Override public IBinder onBind(Intent intent) { Log.i("BindService", "onBind"); return mBinder; } @Override public boolean onUnbind(Intent intent){ Log.i("BindService", "onUnbind"); return true; } @Override public void onDestroy(){ Log.i("BindService", "onDestroy"); } public void TestFunction(){ Log.i("BindService", "適当に作った関数が呼ばれました(^ω^)"); } }
【実行結果】
ライフサイクル通りのログが確認できますね。
アプリを終了させるとBindServiceでonUnbind、onDestroyが呼び出されるのが確認できます。