AIDLの紹介



Introduction Aidl



AIDLとは

AIDLは、Android Interface DefinitionLanguageの略語です。 インタープロセス サービスアクセスによって提供される外部インターフェイス定義。

AIDLをいつ使用するか

Androidの公式ドキュメントには、使用シナリオが記載されています。



Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.

これは、「外部プロセスがサービスにアクセスしたい」および「サービスにマルチスレッド機能がある」場合にのみ使用されます。
単一プロセスでのサービス、バインダーは要件を満たすのに十分であり、マルチスレッドをサポートします。クロスプロセスシングルスレッドの場合は、メッセージを使用できます。

AIDLの使い方

(1)AIDLディレクトリを作成します



画像

(2)IPersoという名前のAIDLファイルを作成します

画像



ASは次のようにコードを自動的に生成します

package com.breakloop.aidlservice // Declare any non-default types here with import statements interface IPerso { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) }

AIDLはJAVAのインターフェース構造に非常に似ていますが、JAVA構文を使用しません。
ASによって生成されたコードは実用的ではありません。 AIDLでサポートされている基本的なタイプをコーダーに伝えるだけです。

(3)2つの方法を設計する

package com.breakloop.aidlservice interface IPerso { int getAge() String getName() }

AIDLファイルを書き込んだ後にプロジェクトを再構築する必要性に特に注意してください。そうしないと、IPersoインターフェイスを実装するときにIPerso.Stubクラスが見つかりません。

(4)IPersoインターフェースを実装する

IPerso.Stubから継承されたPersoクラスを定義します。

public class Perso extends IPerso.Stub { @Override public int getAge() throws RemoteException { return 1 } @Override public String getName() throws RemoteException { return 'breakloop' } }

(5)IPersoインターフェースインスタンスに戻る

カスタムサービスを作成し、onBindでPersoインスタンスを返します。

public class PersoInfo extends Service { private Perso mPerso public PersoInfo() { mPerso=new Perso() } @Override public IBinder onBind(Intent intent) { return mPerso } }

(6)リモートアプリはAIDLを使用します
リモートアプリにAIDLディレクトリを作成し、IPerso.AIDLファイルをこのディレクトリにコピーします。

画像

画像

AIDLファイルの一貫性を確保することは非常に重要です。多くの問題は、AIDLの不整合によって引き起こされます。

(7)インターフェースインスタンスを取得するためのリモートアプリ

public class MainActivity extends AppCompatActivity { private ServiceConnection mServiceConnection private IPerso mPerso @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mServiceConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mPerso=IPerso.Stub.asInterface(iBinder) try { int age =mPerso.getAge() String name=mPerso.getName() String content='Name = '+name+'Age = '+age Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show() Log.i(getClass().getName(), 'onServiceConnected: '+content) } catch (RemoteException e) { e.printStackTrace() } } @Override public void onServiceDisconnected(ComponentName componentName) { } } Intent intent=new Intent('android.intent.action.PERSO') intent.setPackage('com.breakloop.aidlservice') bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE) } }

mPerso = IPerso.Stub.asInterface(iBinder)は、BinderをIPersoエンティティクラスに変換することを強調します。

この時点で、AIDL呼び出しは完了しています。しかし、それは終わっていません!ここに質問があります:カスタムクラスが使用された場合はどうなりますか?

AIDLでカスタムクラスを使用する

(1)カスタムクラスBankCardを作成します

public class BankCard{ public String mCardID public int mAmount public BankCard(){ } }

(2)BankCardがシリアル化を実現

public class BankCard implements Parcelable{ public String mCardID public int mAmount public BankCard(){ } @Override public int describeContents() { return 0 } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public BankCard createFromParcel(Parcel in) { return new BankCard(in) } public BankCard[] newArray(int size) { return new BankCard[size] } } @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(mAmount) parcel.writeString(mCardID) } private BankCard(Parcel in) { mAmount = in.readInt() mCardID=in.readString() } }

(3)BankCardAIDLを作成する
ここで注意すべき2つのポイントがあります
(A)AIDLファイル名がカスタムクラス名と一致しています! ! !
(B)AIDLには、パッケージとシリアル化されたクラス名の2行の情報のみを含める必要があります。 「パーセル可能」は小文字でなければなりません! ! !
AIDLファイルの内容は以下のとおりです。

package com.breakloop.aidlservice parcelable BankCard

プロジェクトを再コンパイルまたは同期してください!プロジェクトにBankCardの存在を認識させてください! !

(4)IPerso.AIDLのBankCardクラスを参照し、BankCardクラスを取得するためのインターフェイスを追加します

package com.breakloop.aidlservice import com.breakloop.aidlservice.BankCard interface IPerso { int getAge() String getName() BankCard getCard() }

(5)BankCardクラスとBankCard.AIDLをリモートアプリにコピーします
パッケージ名は一貫している必要があることに注意してください。

画像

プロジェクトを再コンパイルまたは同期してください! ! ! ! !プロジェクトにインターフェースを更新させましょう! ! !

(6)リモートアプリがインターフェースインスタンスを取得する

@Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mPerso=IPerso.Stub.asInterface(iBinder) try { int age =mPerso.getAge() String name=mPerso.getName() BankCard card=mPerso.getCard() String content='Name = '+name+'Age = '+age+' CardNum = '+card.mCardID+' Amount = '+card.mAmount Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show() Log.i(getClass().getName(), 'onServiceConnected: '+content) } catch (RemoteException e) { e.printStackTrace() } }

これまでのところ、カスタムクラスは正常に呼び出されています。

ただし、カスタムクラスは通常あまり使用されません。 IADLを提供している間、カスタムクラスを出力すると、リリースがより複雑になり、エラーの可能性が高くなります。出力SDKと比較して、利点はありません。