連載
» 2012年04月20日 00時00分 公開

Androidで動く携帯Javaアプリ作成入門(31):Android 4.0のサービス/プロセス間通信の基本 (3/3)

[緒方聡,株式会社イーフロー]
前のページへ 1|2|3       

バイト配列/インスタンスのインターフェイス「Parcelable」

 「Parcelable」とは、Parcelによりバイト配列化、またはバイト配列からインスタンスへと変換が可能になるインターフェイスです。Serializableと似ているのですが、Serializableとは異なり、抽象メソッドを実装しなければいけません。また、決まった名前のフィールドも定義しなければなりません。

Parcelableのコード例

 以下は、サンプルアプリのParcelableの実装です。

public class CalculatorExpression implements Parcelable { // 【1】
    public CalculatorElement mOp;
    public CalculatorElement mLhs;
    public CalculatorElement mRhs;
 
    // 【2】
    public static final Parcelable.Creator CREATOR
         = new Parcelable.Creator() {
        @Override
        public CalculatorExpression createFromParcel(Parcel in) { // 【3】
            return new CalculatorExpression(in);
        }
 
        @Override
        public CalculatorExpression[] newArray(int size) { // 【4】
            return new CalculatorExpression[size];
        }
    };
 
    public CalculatorExpression() {
    }
 
    private CalculatorExpression(Parcel in) { // 【5】
        mOp = (CalculatorElement) in.readSerializable();
        mLhs = (CalculatorElement) in.readSerializable();
        mRhs = (CalculatorElement) in.readSerializable();
    }
 
    @Override
    public void writeToParcel(Parcel out, int flags) { // 【6】
        out.writeSerializable(mOp);
        out.writeSerializable(mLhs);
        out.writeSerializable(mRhs);
    }
 
    @Override
    public int describeContents() { // 【7】
        return 0;
    }
}

 【1】のように、プロセス間通信で受け渡したいクラスにParcelableインターフェイスを実装します。

 【2】のように、ParcelableにはstaticなCREATORという名前のParcelable.Creatorフィールドが必要です。【3】のように、Parcelからインスタンスを生成する実装を行います。【4】のように、配列を生成する実装を行います。

 【5】は、Parcelからデータを読み込んでフィールドを初期化するコンストラクタです。【6】のように、Parcelにデータを書き込むメソッドを実装します。上記の【5】と【6】でデータを読み書きする順番は、常に同じでなければなりません。

 【7】のように、もしこのParcelableにファイルディスクリプタが含まれているのであれば、「CONTENTS_FILE_DESCRIPTOR」を返します。そうでないならば「0」を返します。

 Parcelableは、対象のインスタンスの状態が保持されている最低限のフィールドをParcelに書き込み、読み出せばよいわけです。

bindService()によるサービス生成時のライフサイクル

 ようやくbindService()のライフサイクルの説明です。冒頭の図を再掲します。

図 サービスのライフサイクル 図 サービスのライフサイクル

起動処理

 bindService()の場合も、onCreate()はstartService()の場合と同様、1度しか呼び出されません。

バインドとスタブ

 次に、Service#onBind(Intent)が呼び出されます。

    @Override
    public IBinder onBind(Intent intent) {
        return mStub;
    }

 このメソッドは「IBinder」を返します。startService()の場合は、このメソッドは使わないのでnullを返せばよかったのですが、bindService()ではサービスの実体を返します。

 サンプルのソースコードを見てもらえれば分かると思いますが、コードのほぼすべてが「mStub」の実装です。以下に抜粋して説明します。

    // 【1】
    private ICalculatorService.Stub mStub = new ICalculatorService.Stub() {
        @Override
        public int add(int lhs, int rhs) throws RemoteException { // 【2】
            return lhs + rhs;
        }
    };

 【1】のように、「ICalculatorService.Stub」というクラスを実装したクラスのインスタンスを生成します。ここでは「無名クラス」として実装しています。このICalculatorService.Stubというクラスは「ICalculatorService.aidl」から自動生成されるクラスで、ICalculatorService.aidlで定義したメソッドが「抽象メソッド」として定義されています。

 【2】のように、インターフェイスで定義したメソッドを実装します。ここでは足し算を実装しています。

 このICalculatorService.Stubは「Binder」というクラスを継承していて、BinderはIBinderを実装しています。「ParcelとAIDLで扱えるデータ型」の表を見直してもらえると分かりますが、AIDLでは、IBinderをプロセス間で受け渡しすることが可能で、onBind()で返したIBinderは、プロセスをまたがって呼び出し元に渡されます。

バインドしているサービスから切断

 バインドしているサービスから切断する際には、「Context#unbindService(ServiceConnection)」を呼び出します。この際サービス側ではonUnbind()が呼び出されます。このメソッドは「boolean」を返すようになっており、trueを返すと、次に「bindService()」が呼び出された際に「onRebind()」が、falseを返すと「onBind()」が呼び出される仕組みです。

 「onDestroy()」はバインドしているすべてのクライアントがなくなると呼び出されます。

startService()とbindService()の4つの使い分け

 startService()で実行するサービスは、バックグラウンドで動き続けるという特徴があります。bindService()で実行するサービスとは、相互通信が行えるという特徴があります。

 startService()で実行するサービスは自身で停止できますが、bindService()で実行するサービスはクライアントの接続がなくなるまで停止すべきではありません

 startService()で実行するサービスは、どちらかというと指示を受けた後、自律的に動作するようなケースで使われることが多いのに対し、bindService()で実行するサービスはIPCで明確に指示されて動作するケースとなるでしょう。

 startService()は、どのコンテキストでも呼び出せますが、bindService()はBroadcastReceiverのコンテキストからは呼び出せません

 サービスを使用して何かを実現する場合、startService()でもbindService()でもどちらでも実現可能であるケースが多いと思いますが、上記を参考に設計してみてください。

次回は、サンプルを詳しく解説

 今回は、主にサービスのライフサイクルに関して解説しました。サンプルを添付したものの、今回は、ほとんどその内容に触れていませんでしたが、次回は、サンプルと照らし合わせながら、もう少し踏み込んで「サービス」を解説します。


「Androidで動く携帯Javaアプリ作成入門」バックナンバー
前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。