【Android】サービス(Service)を使ってバックグラウンド処理をする(2)


前回に引き続き、今回もサービス(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クラスの派生クラスを作成します。
ライフサイクルは以下のような感じ。

【Android】サービス(Service)を使ってバックグラウンド処理をする(2):サービス(Service)Bind利用時ライフサイクル

サービス(Service)Bind利用時ライフサイクル



onCreateとonDestroyはバインドを利用しない場合と同じですね。
onStartCommandの代わりに、
  • onBind
  • onUnbind
  • ServiceConnectionクラスのonServiceConnected
の3つが呼び出されます。

【実装例】
・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つで開始と終了を行います。

両方の関数の引数には以下の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", "適当に作った関数が呼ばれました(^ω^)");
  }
}



【実行結果】
【Android】サービス(Service)を使ってバックグラウンド処理をする(2):サンプル実行結果

【Android】サービス(Service)を使ってバックグラウンド処理をする(2):サンプル実行結果ログ

ライフサイクル通りのログが確認できますね。
アプリを終了させるとBindServiceでonUnbind、onDestroyが呼び出されるのが確認できます。


関連記事

コメントは受け付けていません。