ホーム > Android, Android Programming > [android] AIDLによるプロセス間通信

[android] AIDLによるプロセス間通信

2009 年 7 月 18 日 mt コメントをどうぞ コメント

タイトルにあるとおり、Activity – Service間の通信のお話です。

andoridでは、簡単にActivityからServiceのメソッドを実行することができます。

  1. AIDLファイルにIPCのインターフェイスを記述する
  2. Serviceにインターフェイスを実装する
  3. ActivityからServiceにBindし、インターフェイスを叩く

たったこれだけです。

サンプルとして、テキストボックスに入力された値をServiceで加算するプログラムを作ってみます。
こんな感じ。
2009071812

まずはAIDLファイルを作成します。他のJavaソースと同じところに、Interfaceを記述したファイルを配置します。拡張子は.aidlですが、中身はまんまJavaです。


package jp.xfutures.android.sample;

/**
 * サービスのインターフェイス.
 */
interface ISampleService {
    /**
    * 足し算.
    */
    int add(int a, int b);
}

とりあえず、足し算をするだけ。
ファイルを配置すると、自動でgen配下にJavaファイルが生成されます。

2009071811

作成したInterfaceを実装するServiceを作成します。
Service.onBindをオーバーライドしてInterfaceを実装したクラスのインスタンスを返します。


package jp.xfutures.android.sample;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class SampleService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        if(ISampleService.class.getName().equals(intent.getAction())){
            // ISampleServiceの実装クラスのインスタンスを返す
            return sampleSerciceIf;
        }
        return null;
    }

    /**
     * ISampleServiceの実装.
     */
    private ISampleService.Stub sampleSerciceIf = new ISampleService.Stub(){
        @Override
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
    };
}

次は呼び元のActivityを作ります。

bindService()の第2引数にはServiceConnectionの実装を指定します。Bind/Unbind時にこのインスタンスのonServiceConnected()/onServiceDisconnected()が呼ばれます。onServiceConnected()でServiceとのInterfaceを取得できますので、そいつを使ってServiceとやりとりします。
第3引数にBIND_AUTO_CREATEを指定すると、Serviceが未起動の時に起動してくれます。

アプリ終了前にUnbindServiceを忘れずに。


package jp.xfutures.android.sample;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.TextView;

public class SampleActivity extends Activity {

    /** SampleServiceのインターフェイス. */
    private ISampleService sampleServiceIf;

    /**
     * Activityができたよ.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // SampleSericeにbindする
        Intent intent = new Intent(ISampleService.class.getName());
        bindService(
                intent,
                sampleServiceConn,
                BIND_AUTO_CREATE
        );

        // EditTextにonKeyListenerを設定する
        EditText editA = (EditText)findViewById(R.id.EditText01);
        editA.setOnKeyListener(new EditListener());

        EditText editB = (EditText)findViewById(R.id.EditText02);
        editB.setOnKeyListener(new EditListener());
    }

    /**
     * Activityがヤラれたよ.
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();

        // SampleServiceからunbindする
        unbindService(sampleServiceConn);
    }

    /**
     * キー入力されたらアレするやつ.
     */
    private class EditListener implements OnKeyListener{

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            EditText editA = (EditText)findViewById(R.id.EditText01);
            EditText editB = (EditText)findViewById(R.id.EditText02);

            String rslt;
            try{
                int a = Integer.parseInt(editA.getText().toString());
                int b = Integer.parseInt(editB.getText().toString());

                // サービスIFを叩く
                int sum = sampleServiceIf.add(a, b);

                rslt = String.valueOf(sum);
            }
            catch(NumberFormatException e){
                rslt = "数値で";
            }
            catch(RemoteException e){
                // サービスで例外が発生したらRemoteExceptionが飛ぶはず
                rslt = "ダメっ";
            }

            TextView sumText = (TextView)findViewById(R.id.TextView02);
            sumText.setText(String.valueOf(rslt));

            return false;
        }
    }

    /**
     * Serviceに接続・切断したときにアレするやつ.
     */
    private ServiceConnection sampleServiceConn = new ServiceConnection(){

        /**
         * サービスに接続したときに叩かれるメソッド.
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // サービスIFを取得する
            // このIFを使ってサービスとやり取りする
            sampleServiceIf = ISampleService.Stub.asInterface(service);
        }

        /**
         * サービスから切断したときに叩かれるメソッド.
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {
            sampleServiceIf = null;
        }
    };
}

最後になっていまいましたが、AndroidManifest.xmlにInterfaceを記述してあげます。
こいつを記述しないと動きませんので、忘れないように。


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="jp.xfutures.android.sample"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".SampleActivity"
                  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="SampleService">
            <intent-filter>
                <!-- これを忘れないように!! -->
                <action android:name="jp.xfutures.android.sample.ISampleService"></action>
            </intent-filter>
        </service>
    </application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>

まとめ。
AndroidSample2009071801.zip

関連する投稿:

Post to Twitter Post to Delicious Post to Facebook Post to MySpace

  1. master
    2009 年 12 月 21 日 19:26 | #1

    参考にさせていただいています。

    ご存知でしたら教えていただきたいのですが、
    androidのサービスをSDKのような形で提供して、
    それをActivityを含むアプリケーションから実行できるように
    したいと考えているのですが、可能なのでしょうか?

  2. 2009 年 12 月 23 日 22:17 | #2

    @master
    できると思いますよ。
    サービス側で作ったAIDLファイルを利用者に配布すれば良いかと。

  3. master
    2010 年 1 月 19 日 16:24 | #3

    回答ありがとうございます。

    返信遅くなりました。
    なるほど、AIDLファイルを提供するわけですね。

    頑張ってみます!

  4. hanzo
    2010 年 5 月 11 日 14:23 | #4

    いつも参考にさせていただいております。

    一つ質問なのですが、Eclipse上で開発する際、AIDLを持ったサービスと、AIDLファイルを利用するActivityを別プロジェクトとして開発する場合、AndroidManifest.xmlにはどのように記載すればよいのでしょうか?

  5. mt
    2010 年 5 月 11 日 22:21 | #5

    @hanzo
    プロジェクトが異なっていても、AndroidManifestの記述内容は同じですよ。
    こちらにサンプルをあげましたので、参考にしてみてください。

  6. hanzo
    2010 年 5 月 13 日 09:35 | #6

    サンプル有難う御座います。
    早速試してみて、動くこと確認できました?。

  1. 2009 年 8 月 16 日 06:24 | #1
  2. 2010 年 5 月 11 日 22:16 | #2