バイト配列/インスタンスのインターフェイス「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()でもどちらでも実現可能であるケースが多いと思いますが、上記を参考に設計してみてください。
次回は、サンプルを詳しく解説
今回は、主にサービスのライフサイクルに関して解説しました。サンプルを添付したものの、今回は、ほとんどその内容に触れていませんでしたが、次回は、サンプルと照らし合わせながら、もう少し踏み込んで「サービス」を解説します。
- グーグルのAPIを使うときに欠かせないGoogle OAuthの作り方と使い方
- 細か過ぎて伝わってないけど開発者が知っておきたいAndroid Mの新機能まとめ
- 腕時計から電話をかけるAndroid Wearアプリの作り方
- Android Wear用アプリの花形、時計アプリ「Watch Face」の基本的な作り方
- Android 5.0発表&スマホと連動する音声認識Android Wearアプリの作り方
- ウェアラブル端末用Android Wearアプリ開発の基礎知識
- 変わらないと生き残れないAndroid Lの新機能まとめ
- Android WearやIoTで注目のAndroidセンサー機能8選
- ウェアラブル時代に見直したいAndroidの加速度/重力センサー、ジャイロスコープ
- あなたの知らないAndroid SDKの便利tools、14選まとめ
- Android 4.4のメモリ使用状況を把握する3つのツールの使い方
- Androidでリアルタイムマルチプレーゲームを開発するには
- 低性能端末でも使えるか? Android 4.4 KitKatの新機能39選
- もはや無料BaaS。ゲーム以外でも使いたくなるGoogle Play Game Servicesのデータ管理機能
- アプリにGoogle+のソーシャルグラフを持ち込めるGoogle Play Game Servicesの基礎知識
- あなたのアプリはクラウドにデータをバックアップできますか?
- Eclipse ADTに代わるIDEとなるか? Android Studioの基礎知識
- ActionBarで、アプリのUIはこんなにスマートになる
- Android 4.x時代のアプリにないと残念なActionBarとは
- 動的クラスローディングでAndroidアプリ“裏”開発
- Android 4.xのAndroidビームをアプリに組み込むには
- AndroidアプリでNFCタグを読み書きするための基礎知識
- 新タブレット時代を見据えるAndroid 4.2の新機能9選
- Androidからイヤフォンやヘルス機器とBluetooth通信するには
- Bluetoothを使ってAndroidアプリ同士で通信するには
- Androidアプリをアプリ内購読に対応してもうける方法
- 開発者が知らないと残念過ぎるAndroid 4.1の新機能36選
- Androidのプロセス間通信を自由自在にするAIDL
- Android 4.0のサービス/プロセス間通信の基本
- Androidアプリでマルチメディアを扱うための基礎知識
- Androidのウィジェットにノーティフィケーションするには
- Android 4.0で注目の顔認識をアプリに組み込むには
- Android 4.0でアプリ開発を始めるための環境構築
- 開発者が知らないと損するAndroid 4.0の新機能44選
- Android Compatibility packageで2.x系でもマルチサイズ対応
- Androidの画面の大きさの違いを解決するFragments
- Android 3.0の新APIで簡単ドラッグ&ドロップ実装
- 開発者が知って得するAndroid 2.3の新機能18選
- アニメーションでAndroidに独創的な画面エフェクトを
- Androidアプリで“アニメーション”するための基礎知識
- XMLレイアウトでAndroidアプリに“設定画面”を追加
- 開発者が知っておきたいAndroid 2.2の新機能12連発
- もはやケータイに必須のカメラをAndroidで制御しよう
- 地図/位置情報/GPSを使うAndroidアプリを作るには
- Android NDKでJNIを使用してアプリを高速化するには
- Android 2.1の新機能「Live Wallpaper」で作る、美しく燃える“待ち受け”
- iPhoneより多彩なAndroidのセンサをアプリで操作
- SurfaceViewならAndroidで高速描画ゲームが作れる
- Android 1.6のジェスチャーとテキスト読み上げを使う
- Androidのホーム画面に常駐するアプリを作るには
- Netbookにも広まるAndroidで、かつてないWeb体験を
- アプリを国際化してAndroid Marketから世界へ発信
- 常駐アプリが作成できるAndroidの“サービス”とは
- AndroidでSQLiteのDB操作をするための基礎知識
- Androidアプリの使いやすさを左右する5つのレイアウト
- 簡単でワクワクするAndroidウィジェット10連発!
- ブラウザや地図、ストリートビューの基、Intentとは?
- Androidアプリ作成の基本“Activity”とは何か?
- Android Market配布を目指しEclipseでHelloWorld!
Copyright © ITmedia, Inc. All Rights Reserved.