Androidで、AIDL(Android Interface Definition Language)を使って
別プロセスとして定義したサービスのメソッドを呼びだして遊んで見ました。
作ってみたソースは、このページのずっと下にリンクがあります。
動作概要
クライアントから、サービスプロセスの動作周期を設定し、
サービスは、設定された周期で、クライアントに向けてインテントを発行。
クライアントはインテント受信をトリガにして、
メモリ情報を画面表示するというシンプルなサンプル。
クライアント名:SimpleIPCActivity
サービス名:IKickStarterService
AIDL
AIDLの定義。
クライアント側へ公開するメソッドの定義。
package sample.com.ipc;
interface IKickStarterService {
void stopService();
void setPeriod(int period);
}
マニフェスト
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="sample.com.ipc"
android:versionCode="1"
android:versionName="1.0" >
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".SimpleIPCActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".KickStarterService" android:process=":service">
<intent-filter>
<action android:name="sample.com.ipc.KickStarterService"></action>
</intent-filter>
</service>
</application>
<uses-sdk android:minSdkVersion="10" />
</manifest>
クライアント(サービスの起動と、バインド)
クライアントの初期起動時、サービスの起動とバインドを同時に行う。
以後、サービスの停止、再起動動作、リバインド動作は行わない...。
@Override
public void onCreate(Bundle savedInstanceState) {
~~~~~~~~~略~~~~~~~~~~~
Intent intent = new Intent(SimpleIPCActivity.this, KickStarterService.class);
startService(intent);
// サービスに接続
bindService(intent, connection, BIND_AUTO_CREATE);
receiver = new Receiver();
IntentFilter filter = new intentFilter(KickStarterService.INTENT_ACTION);
registerReceiver(receiver, filter);
}
クライアント(バインド完了時の動作)
バインドが、完了したときに起動されるコールバックを定義する。
ここで、サービスを参照できるバインドオブジェクトを取得する。
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = IKickStarterService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
binder = null;
}
};
クライアント(サービスメソッドの読み出し)
"Start"ボタン押下時、サービスの起動周期を設定、
"Stop"ボタン押下時、サービスが内部で保持するタイマ停止要求発行
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button start_btn = (Button)findViewById(R.id.btnStart);
start_btn.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
try {
EditText editPeriod = (EditText)findViewById(R.id.period_edit);
int period = Integer.parseInt(editPeriod.getText().toString());
binder.setPeriod(period*1000);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
// サービス停止
Button stop_btn = (Button)findViewById(R.id.btnStop);
stop_btn.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
if( binder != null ) {
try {
binder.stopService();
} catch(RemoteException e) {
e.printStackTrace();
}
}
}
});
クライアント(ブロードキャストレシーバ)
サービスからの周期インテントレシーバ
インテント受信時、本体のメモリ情報を画面表示する。
private class Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// アプリのメモリ情報を取得
Runtime runtime = Runtime.getRuntime();
TextView totalmemory = (TextView)findViewById(R.id.totalmemory);
TextView freememory = (TextView)findViewById(R.id.freememory);
TextView usedmemory = (TextView)findViewById(R.id.usedmemory);
TextView dalvikmemory = (TextView)findViewById(R.id.dalvikmemory);
int value = (int)(runtime.totalMemory()/1024);
totalmemory.setText(" : "+String.valueOf(value)+"kbyte");
value = (int)(runtime.freeMemory()/1024);
freememory.setText(" : "+String.valueOf(value)+"kbyte");
value = (int)((runtime.totalMemory() - runtime.freeMemory())/1024);
usedmemory.setText(" : "+String.valueOf(value)+"kbyte");
value = (int)(runtime.maxMemory()/1024);
dalvikmemory.setText(" : "+String.valueOf(value)+"kbyte");
}
}
サービス
package sample.com.ipc;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class KickStarterService extends Service {
public static final String INTENT_ACTION = "KickStarterService_Update";
private Timer timer;
private int period=1000;
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
return IKickStarterServiceBinder;
}
public void updateTask(long period) {
if( timer != null ) {
timer.cancel();
}
timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
sendBroadcast(new Intent(INTENT_ACTION));
}
};
timer.schedule(task, 0, this.period);
}
@Override
public void onDestroy() {
super.onDestroy();
if( timer != null ) {
timer.cancel();
timer = null;
}
}
private final IKickStarterService.Stub IKickStarterServiceBinder = new IKickStarterService.Stub() {
public void stopService() throws RemoteException {
if( timer != null ) {
timer.cancel();
timer = null;
}
}
@Override
public void setPeriod(int freq) throws RemoteException {
// TODO Auto-generated method stub
period = freq;
updateTask(period);
}
};
}