以下はサービスのAIDLファイルです。この内容を見れば、前ページで説明していることがだいたい分かります。
package com.example.android.service; import com.example.android.service.ICalculatorCallback; import com.example.android.service.CalculatorExpression; interface ICalculatorService { /** * コールバック登録。 * @param callback 登録するコールバック。 */ oneway void registerCallback(ICalculatorCallback callback); /** * コールバック解除。 * @param callback 解除するコールバック。 */ oneway void unregisterCallback(ICalculatorCallback callback); /** * 同期の加算。 * @param lhs 加算対象 * @param rhs 加算対象 * @return 加算結果 */ int add(int lhs, int rhs); /** * 非同期の合算。 * 合算結果はコールバックで通知される。 * @see ICalculator#resultSum(int) */ void sum(in List values); /** * 同期のローテーション。 * ローテーション結果は引数に反映される。 * @param array ローテーション対象。 * @param num ローテーション数。プラスで右、マイナスで左にローテーション */ void rotate(inout int[] array, int num); /** * 同期の計算。任意の四則演算が行える。 * @param exp 計算式 * @return 計算結果 */ int eval(in CalculatorExpression exp); }
なお、各メソッドにJavadocが記述してありますが、このようにしておくと、自動生成されたJavaソースコードにもJavadocが反映され、Eclipse上でメソッドの説明を見ることができるようになります。
.adilの文法に関しては、前回の記事内の「プロセス間通信用インターフェイス定義言語『AIDL』」を参照してください。
このサービスの実装の抜粋コードを以下に示します。
package com.example.android.service; public class CalculatorService extends Service { private ICalculatorService.Stub mStub = new ICalculatorService.Stub() { //【1】 @Override public int add(int lhs, int rhs) throws RemoteException { //【2】 return lhs + rhs; } }; @Override public IBinder onBind(Intent intent) { return mStub; //【3】 } }
サービスは自動生成された抽象クラスStubを実装がなければなりません。【1】のように匿名クラスで実装するのが簡単です。AIDLファイルで定義したインターフェイスをこの匿名クラスで【2】のように実装します。Stubの実装をonBind(Intent)の戻り値として【3】のように返します。
サービスの実装は、これだけです。
サービスのクライアントとなるActivityの実装の抜粋コードを以下に示します。
package com.example.android.service; public class ClientActivity extends Activity { private Handler mHandler; private ICalculatorCallback mCallback = new ICalculatorCallback.Stub() { //【1】 @Override public void resultSum(final int value) throws RemoteException { mHandler.post(new Runnable() { public void run() { mTextViewResult.setText("Result:" + value); } }); } }; private ServiceConnection mServiceConnection = new ServiceConnection() { //【2】 @Override public void onServiceDisconnected(ComponentName name) { mService = null; } @Override public void onServiceConnected( ComponentName name, IBinder service) { //【3】 mService = ICalculatorService.Stub.asInterface(service); //【4】 } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); bindService(new Intent(ICalculatorService.class.getName()), //【5】 mServiceConnection, BIND_AUTO_CREATE); //【6】 } @Override protected void onDestroy() { super.onDestroy(); if (mService != null) { unbindService(mServiceConnection); //【7】 } } public void onClick(View view) throws NumberFormatException, RemoteException { int result = mService.add(1, 2); //【8】 } }
Serviceではサービスの実体を“Stubの継承”で作成しましたが、Activityではコールバックの実体を、コールバックのStubを継承して【1】のように実装します。サービスの実装とまったく同じです。上記の抜粋したコードでは省略していますが、ここで生成したコールバックをサービスに渡すことで、サービスからコールバック呼び出しが可能になるわけです。
AIDLを使用するサービスとのプロセス間通信では、【2】のようにServiceConnectionを実装する必要があります。これも、匿名クラスとして実装するのが簡単です。このクラスはサービスと接続した際に呼び出されるメソッド、サービスと切断した際に呼び出されるメソッドをそれぞれ実装する必要があります。
重要なのは接続した方で、これが【3】のonServiceConnectedです。この中では【4】のように自動生成されたStubクラスの静的メソッドでサービスを取得します。
ServiceConnectionでサービスに接続するには、【6】のようにbindService(...)にインスタンスを渡します。【5】で指定するアクションはサービスごとに決められたものである必要があり、今回のケースではAndroidManifest.xmlで指定したクラス名とします。
サービスとの切断を行うには、unbindService(...)にServiceConnectionのインスタンスを【7】のように渡します。
サービスを呼び出すには、ServiceConnectionで取得したサービスのインスタンスのメソッドを【8】のように直接呼び出します。
次ページでは、ParcelableとSerializable、そして「IntentService」について説明します。
Copyright © ITmedia, Inc. All Rights Reserved.