IBind によるアクティビティとサービスの接続

ここではアクティビティとサービスの接続を行う方法をしめします。

この方法を使うとサービス内に実装したメソッドをアクティビティから呼ぶことができます。

バインダーの実装

次のようにして Binder から派生したクラスを、このサービスクラスのバインダーとして作成します。

アクティビティ側でサービスをバインドしたときに、Binder の IBind インターフェイスを取得でき、それをもとにサービスのインスタンスにアクセスできるようになります。

package com.keicode.android.test;

import android.app.IntentService;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class MyIntentService extends IntentService {

  final static String TAG = "ServiceTest6";
  final IBinder binder = new MyBinder();
  String message;
  
  public class MyBinder extends Binder {
    MyIntentService getService(){
      return MyIntentService.this;
    }    
  }
  
  public MyIntentService() {
    super(TAG);
  }

  public void setMessage(String message){
    this.message = message;
  }

  @Override
  public IBinder onBind(Intent intent) {
    Log.d(TAG, "onBind");
    return binder;
  }

  @Override
  protected void onHandleIntent(Intent intent) {
    Log.d(TAG, "onHandleIntent");
    Log.d(TAG, "message = [" + message + "]");
    try {
      Thread.sleep(10000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }    
  }

}

サービスの起動側は、次のようになります。

package com.keicode.android.test;

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 ServiceTest6 extends Activity {

  final static String TAG = "ServiceTest6";

  Button startButton;
  MyIntentService myService;
  Intent serviceIntent;

  ServiceConnection serviceConnection = new ServiceConnection(){
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      Log.d(TAG, "onServiceConnected");
      myService = ((MyIntentService.MyBinder)service).getService();
      myService.setMessage("Hello, IBinder!");
      startService(serviceIntent);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
      Log.d(TAG, "onServiceDisconnected");
      myService = null;
    }
  };
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    startButton = (Button)findViewById(R.id.start_button);
    startButton.setOnClickListener(new OnClickListener(){
      @Override
      public void onClick(View v) {
        serviceIntent = new Intent(
          getBaseContext(), MyIntentService.class);
        bindService(
          serviceIntent, serviceConnection, 
          Context.BIND_AUTO_CREATE);
      }
    });
  }
  
}

直ちに startService せずに、先に bindService を呼び出し ServiceConnection の onServiceConnected メソッドを呼び出させておき、 そこで startService します。

実行結果は次の通り。

IBind - Android サービス

別プロセスで実行する場合は・・・ AIDL

尚ここの方法では、サービスを別プロセスで実行すると、onServiceConnected で MyIntentService.MyBinder にキャストするところで失敗します。 別プロセスの場合この IBinder は android.os.BinderProxy のものになるためです。従って別プロセスで実行する場合は AIDL による IPC を検討すると良いです。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門