たぼさんの部屋

いちょぼとのんびり

SECTION234 バインドとコールバックでプロセス間通信

f:id:donsuka_kk:20121212161824p:plainf:id:donsuka_kk:20121212161831p:plain

コールバックを行うにはコールバックインターフェースを使用する

アクティビティの画面更新などサービスからアクティビティへの通知が必要な仕組みを提供するのがコールバックです。

流れ

  • アクティビティからサービスをバインドする
  • コールバックを登録するインターフェースを呼び出す
  • 呼び出したインターフェースで、コールバック情報をリストに登録する
  • リストを参照して登録されているコールバックインターフェースをコールする
  • アクティビティに実装したコールバックインターフェースで画面更新などを行う

実装手順

上の流れを元にしたコールバックの実装手順は

  • 1 [AIDL]コールバックインターフェースを定義する
  • 2 [AIDL]コールバックインターフェースを登録するメソッドを定義する
  • 3 [Service]コールバックインターフェースと登録するメソッドを実装する
  • 4 [Service]登録されたコールバックを呼び出す処理を実装する
  • 5 [Activity]コールバックインターフェースをアクティビティに実装する
  • 6 [Activity]コールバックを登録する処理を実装する

サンプルプログラムでは

  • 1 ISampleService.aidlのregisterCallbackメソッド
  • 2 IsampleCallback.aidlのupdateTextメソッド
  • 3 CallbackService.javaのregisterCallbackメソッド
  • 4 CallbackService.javaのhandleMessageメソッド
  • 5 Mainの以下の部分

private ISampleCallback callback = new ISampleCallback.Stub(){
//処理
}

  • 6 Mainの以下の部分

private ServiceConnection con = new ServiceConnectiont(){
//処理
}

ISampleCallback.aidl

package com.efolab.s234;

oneway interface ISampleCallback {
	// テキストビュー更新処理
	void updateText(String value);
}

ISampleService.aidl

package com.efolab.s234;

import com.efolab.s234.ISampleCallback;

oneway interface ISampleService {
	// コールバックインターフェース登録処理
	void registerCallback(ISampleCallback callback);
	
	// コールバックインターフェース登録解除処理
	void unregisterCallback(ISampleCallback callback);
}

Main.java

package com.efolab.s234;

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.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.widget.LinearLayout;
import android.widget.TextView;

public class Main extends Activity {
	Context context;
	LinearLayout base;
	TextView textview;
	// サービスのインターフェイス宣言
	private ISampleService serviceIf;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		context = getApplicationContext();
		base = new LinearLayout(context);
		setContentView(base);
		textview = new TextView(context);
		base.addView(textview);
		// サービスへのバインド処理
		Intent intent = new Intent(ISampleService.class.getName());
		bindService(intent, con, BIND_AUTO_CREATE);
	}
	@Override
	protected void onDestroy() {
		super.onDestroy();
		// コールバック登録解除処理
		try {
			serviceIf.unregisterCallback(callback);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		// サービスのアンバインド処理
		unbindService(con);
	}
	// サービスの接続
	private ServiceConnection con = new ServiceConnection(){
		// サービス接続処理
		public void onServiceConnected(ComponentName name, IBinder service) {
			// サービスのインターフェースを取得
			serviceIf = ISampleService.Stub.asInterface(service);
			try {
				serviceIf.registerCallback(callback);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
		// サービス切断処理
		public void onServiceDisconnected(ComponentName name) {
			serviceIf = null;
		}
	};
	// ハンドラメッセージ受け取り処理
	private Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			// メッセージ出力
			String text = (String)msg.obj;
			textview.setText(text);
			if(text.equals("サービスが終了しました!")) {
				// コールバック登録解除処理
				try {
					serviceIf.unregisterCallback(callback);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		}
	};
	// コールバックインターフェースの実装
	private ISampleCallback callback = new ISampleCallback.Stub(){
		public void updateText(String value) throws RemoteException {
			// 受け取ったメッセージを画面に設定
			handler.sendMessage(Message.obtain(handler, 0, value));
		}
	};
}

CallbackService.java

package com.efolab.s234;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;

public class CallbackService extends Service {
	// サービスの継続時間設定(秒)
	private int count = 10;
	// コールバックインターフェース設定
	private final RemoteCallbackList<ISampleCallback> list
		= new RemoteCallbackList<ISampleCallback>();
	// ハンドラ処理
	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == 1) {
				int numListeners = list.beginBroadcast();
				for (int i = 0; i < numListeners; i++) {
					try {
						if(count == 0) {
							list.getBroadcastItem(i).updateText("サービスが終了しました!");
						} else {
							list.getBroadcastItem(i).updateText("サービス終了まで " + count + "秒");
						}
					} catch (RemoteException e) {
					}
				}
				list.finishBroadcast();
				// 1秒毎にメッセージを送信
				handler.sendEmptyMessageDelayed(1, 1 * 1000);
				count--;
			} else {
				super.dispatchMessage(msg);
			}
		}
	};
	@Override
	public void onCreate() {
		super.onCreate();
		handler.sendEmptyMessage(1);
	}
	@Override
	public IBinder onBind(Intent intent) {
		if(ISampleService.class.getName().equals(intent.getAction())){
			return sampleSerciceIf;
		}
		return null;
	}
	// ISampleServiceの実装
	private ISampleService.Stub sampleSerciceIf = new ISampleService.Stub(){
		public void registerCallback(ISampleCallback callback)
			throws RemoteException {
			// コールバックリスト登録処理
			list.register(callback);
		}
		public void unregisterCallback(ISampleCallback callback)
			throws RemoteException {
			// コールバックリスト登録解除処理
			list.unregister(callback);
		}
	};

}