別のプロセスで実行されているサービスを持つサンプルアプリケーションが含まれています。
記事は次のように考えるべきです:
- リモートAndroidサービスとAIDLを使用したアプリケーションのアーキテクチャの例。
- 便利なコード例。
- Android Developersのメインドキュメントへの追加としてのみ(記事の最後にあるリンクを参照)。
基本的な概念
サービスは、ユーザーインターフェイスのないAndroidアプリケーションのコンポーネントであり、リソースを大量に消費する操作や長時間の操作を実行するように設計されています。
Androidサービスの種類
- 開始済み-他のアプリケーションコンポーネント(Activity、BrodcastReceiver、Service)によって起動され、自分自身を停止するか誰かが停止するまで機能するサービス。
- バウンド(関連)-クライアントサーバーアーキテクチャでサーバーとして機能するサービス。 このようなサービスは、アプリケーションの別のコンポーネントからの最初の接続(要求)で作成され、最後のクライアントが切断されると停止します。
- サービスは、開始とバインドの両方にできます。 このようなサービスは、「永久に存続」し、顧客の要求に応えることができます。
サービスは、アクティビティとは別のプロセスで起動できます。
利点:
- 最大メモリサイズは2倍に増加します。たとえば、32 MB /プロセス(プラットフォームに依存)
- スナップショットのあるプロセスが2つあり、それぞれが1 MBと2 * N MBである場合、GCの動作はそれほど激しくありません。
- Androidサービスの標準的な利点:バックグラウンド、アクティビティからの独立など。
短所:
- 低レベルのシリアル化と逆シリアル化のための追加のシステムリソース。
- プロセスのライフサイクルを制御する必要性。
- もう少しコード。
エイドル
リテラル翻訳-Androidインターフェースの説明用の言語。 プロセス間の直接転送のために、JavaオブジェクトのOSプリミティブへの構成と分解を記述するために使用されます。
AIDLファイルは、次の例外を除いて、Javaの標準インターフェースに非常に似ています。
- 同じパッケージ内にあるaidlファイルもインポートする必要があります。
- voidメソッド宣言のonewayキーワードは、メソッドが非同期に呼び出されることを意味します(クライアントは実行を待機しません)。
- 他のエイドルファイルで宣言されているプリミティブ、String、List、およびParcelableクラスのみを使用できます。
AIDLを使用して、スタブを生成するJavaコードが自動的に生成されます。
アプリケーションアーキテクチャ
私たちが開発したアプリケーションは、メモリカードと写真共有ネットワークから写真を表示できるAndroidのギャラリーです。
このアプリケーションのサービスの主な目的は、メタデータ(アルバム、写真、友人に関する情報)の取得、更新プログラム、およびそれらに関連する他のすべての監視です。 このサービスは常に関連情報を保存し、いつでもメインアクティビティに提供して表示する準備ができています。
コードの主要なセクションを以下に示し、プリミティブサービスを作成するプロセスについて説明します。
次のAIDLファイルは、サービスとアクティビティ間の通信に使用されます。
IDataSourceService.aidl-サービスインターフェイス:
packagecom.umobisoft.habr.aidlexample.common; import com.umobisoft.habr.aidlexample.common.IDataSourceServiceListener; interfaceIDataSourceService{ voidloadAlbums(in IDataSourceServiceListener listener); … }
IDataSourceServiceListener.aidl-サービスからのメッセージのリスナーのインターフェイス:
package com.umobisoft.habr.aidlexample.common; import com.umobisoft.habr.aidlexample.common.pojo.Album; interface IDataSourceServiceListener{ oneway void albumItemLoaded(in Album a); }
データは、Parcelableインターフェイスを実装する2つのクラス-AlbumとPhotoを使用して送信されます。 これらのクラスのaidlファイルの宣言が必要です。 OSプリミティブからJavaオブジェクトに変換する場合、Creatorクラスが使用されます。
データを書き込むには、ParcelableインターフェイスのwriteToParcelメソッドを使用します。
@Override public void writeToParcel(Parcel out, int flags) { try{ out.writeLong(id); out.writeString(name); out.writeTypedList(photos); }catch (Exception e) { Log.e(TAG, "writeToParcel", e); } }
describeContentsという補助メソッドもあります。そのタスクは、シリアル化とデシリアライゼーションに使用できるオブジェクトの特殊なケース/状態を記述することです。
@Override public int describeContents() { // TODO Auto-generated method stub return 0; }
データを読み取る方法は、データをParcelableインターフェースに入れるのにふさわしくないことが判明しましたが、標準的な方法では、Creatorを次のものと組み合わせて使用します。
private void readFromParcel(Parcel in) { try{ id = in.readLong(); name = in.readString(); photos.clear(); in.readTypedList(photos, Photo.CREATOR); }catch (Exception e) { Log.e(TAG, "readFromParcel", e); } }
アクティビティはonCreateメソッドでサービスを開始します(したがって、StartedServiceにします)。
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textView = (TextView)findViewById(R.id.album_text); Intent serviceIntent = newIntent(this, DataSourceService.class); startService(serviceIntent); connectToService(); }
ライフサイクルの同じ段階で、サービスに接続します。
private void connectToService() { Intent intent = newIntent(this, DataSourceService.class); this.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); }
サービスに接続するプロセスは非同期であり、ServiceConnectionインターフェイスの実装を実装します。 サーバーへの接続中、IDataSourceServiceListener.Stubの実装を使用して、アクティビティがメッセージリスナーとしてサービスに登録されます。
private ServiceConnection serviceConnection = newServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, "Service connection established"); serviceApi = IDataSourceService.Stub.asInterface(service); try { mainListener = newIDataSourceServiceListener.Stub() { @Override publicvoidalbumItemLoaded(final Album a) throwsRemoteException { mToastHandler.post(new Thread(){ publicvoid run(){ Toast.makeText(HabrahabrAIDLExampleActivity.this, a.toString(), Toast.LENGTH_LONG).show(); textView.setText(a.toString()); } }); } }; serviceApi.loadAlbums(mainListener); } catch (RemoteException e) { Log.e(TAG, "loadAlbums", e); } } @Override publicvoidonServiceDisconnected(ComponentName name) { Log.i(TAG, "Service connection closed"); serviceApi = null; connectToService(); } };
StartedServiceの実行中に、空きメモリの量が特定のしきい値まで減少すると、システムは警告なしにサービスを強制終了できます。 その後、システムはサービスを再起動する必要があります。 したがって、onServiceDisconnectedメソッドでは、サービスとの接続を再度初期化します。
レイアウトされたソースコードが、開発者がAIDLに慣れるのに役立つことを期待しています。 完全な例のあるアーカイブはこちらです。
メインアプリケーションは、 Androidマーケットで表示できます。
AndroidDevelopersの公式ドキュメント:
サービス: developer.android.com/guide/topics/fundamentals/services.html
AIDL: developer.android.com/guide/developing/tools/aidl.html