版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
1、Android的AIDL通信機制Android 接口定義語言 (AIDL)AIDL(Android 接口定義語言)與您可能使用過的其他 IDL 類似。 您可以利用它定義客戶端與服務使用進程間通信 (IPC) 進行相互通信時都認可的編程接口。 在 Android 上,一個進程通常無法訪問另一個進程的內(nèi)存。 盡管如此,進程需要將其對象分解成操作系統(tǒng)能夠識別的原語,并將對象編組成跨越邊界的對象。 編寫執(zhí)行這一編組操作的代碼是一項繁瑣的工作,因此 Android 會使用 AIDL 來處理。注:只有允許不同應用的客戶端用 IPC 方式訪問服務,并且想要在服務中處理多線程時,才有必要使用 AIDL。 如果
2、您不需要執(zhí)行跨越不同應用的并發(fā) IPC,就應該通過實現(xiàn)一個 Binder 創(chuàng)建接口;或者,如果您想執(zhí)行 IPC,但根本不需要處理多線程,則使用 Messenger 類來實現(xiàn)接口。無論如何,在實現(xiàn) AIDL 之前,請您務必理解綁定服務。在您開始設計 AIDL 接口之前,要注意 AIDL 接口的調(diào)用是直接函數(shù)調(diào)用。 您不應該假設發(fā)生調(diào)用的線程。 視調(diào)用來自本地進程還是遠程進程中的線程,實際情況會有所差異。具體而言:來自本地進程的調(diào)用在發(fā)起調(diào)用的同一線程內(nèi)執(zhí)行。如果該線程是您的主 UI 線程,則該線程繼續(xù)在 AIDL 接口中執(zhí)行。 如果該線程是其他線程,則其便是在服務中執(zhí)行您的代碼的線程。 因此,只
3、有在本地線程訪問服務時,您才能完全控制哪些線程在服務中執(zhí)行(但如果真是這種情況,您根本不應該使用 AIDL,而是應該通過實現(xiàn) Binder 類創(chuàng)建接口)。來自遠程進程的調(diào)用分派自平臺在您的自有進程內(nèi)部維護的線程池。 您必須為來自未知線程的多次并發(fā)傳入調(diào)用做好準備。 換言之,AIDL 接口的實現(xiàn)必須是完全線程安全實現(xiàn)。oneway 關鍵字用于修改遠程調(diào)用的行為。使用該關鍵字時,遠程調(diào)用不會阻塞;它只是發(fā)送事務數(shù)據(jù)并立即返回。接口的實現(xiàn)最終接收此調(diào)用時,是以正常遠程調(diào)用形式將其作為來自 Binder 線程池的常規(guī)調(diào)用進行接收。 如果 oneway 用于本地調(diào)用,則不會有任何影響,調(diào)用仍是同步調(diào)用。
4、定義 AIDL 接口您必須使用 Java 編程語言語法在 .aidl 文件中定義 AIDL 接口,然后將它保存在托管服務的應用以及任何其他綁定到服務的應用的源代碼(src/ 目錄)內(nèi)。您開發(fā)每個包含 .aidl 文件的應用時,Android SDK 工具都會生成一個基于該 .aidl 文件的 IBinder 接口,并將其保存在項目的 gen/ 目錄中。服務必須視情況實現(xiàn) IBinder 接口。然后客戶端應用便可綁定到該服務,并調(diào)用 IBinder 中的方法來執(zhí)行 IPC。如需使用 AIDL 創(chuàng)建綁定服務,請執(zhí)行以下步驟:創(chuàng)建 .aidl 文件此文件定義帶有方法簽名的編程接口。實現(xiàn)接口Andro
5、id SDK 工具基于您的 .aidl 文件,使用 Java 編程語言生成一個接口。此接口具有一個名為 Stub 的內(nèi)部抽象類,用于擴展 Binder 類并實現(xiàn) AIDL 接口中的方法。您必須擴展 Stub 類并實現(xiàn)方法。向客戶端公開該接口實現(xiàn) Service 并重寫 onBind() 以返回 Stub 類的實現(xiàn)。注意:在 AIDL 接口首次發(fā)布后對其進行的任何更改都必須保持向后兼容性,以避免中斷其他應用對您的服務的使用。 也就是說,因為必須將您的 .aidl 文件復制到其他應用,才能讓這些應用訪問您的服務的接口,因此您必須保留對原始接口的支持。1. 創(chuàng)建 .aidl 文件AIDL 使用簡單語
6、法,使您能通過可帶參數(shù)和返回值的一個或多個方法來聲明接口。 參數(shù)和返回值可以是任意類型,甚至可以是其他 AIDL 生成的接口。您必須使用 Java 編程語言構建 .aidl 文件。每個 .aidl 文件都必須定義單個接口,并且只需包含接口聲明和方法簽名。默認情況下,AIDL 支持下列數(shù)據(jù)類型:Java 編程語言中的所有原語類型(如 int、long、char、boolean 等等)StringCharSequenceListList 中的所有元素都必須是以上列表中支持的數(shù)據(jù)類型、其他 AIDL 生成的接口或您聲明的可打包類型。 可選擇將 List 用作“通用”類(例如,List)。另一端實際接
7、收的具體類始終是 ArrayList,但生成的方法使用的是 List 接口。MapMap 中的所有元素都必須是以上列表中支持的數(shù)據(jù)類型、其他 AIDL 生成的接口或您聲明的可打包類型。 不支持通用 Map(如 Map 形式的 Map)。 另一端實際接收的具體類始終是 HashMap,但生成的方法使用的是 Map 接口。您必須為以上未列出的每個附加類型加入一個 import 語句,即使這些類型是在與您的接口相同的軟件包中定義。定義服務接口時,請注意:方法可帶零個或多個參數(shù),返回值或空值。所有非原語參數(shù)都需要指示數(shù)據(jù)走向的方向標記??梢允?in、out 或 inout(見以下示例)。原語默認為 i
8、n,不能是其他方向。注意:您應該將方向限定為真正需要的方向,因為編組參數(shù)的開銷極大。.aidl 文件中包括的所有代碼注釋都包含在生成的 IBinder 接口中(import 和 package 語句之前的注釋除外)只支持方法;您不能公開 AIDL 中的靜態(tài)字段。以下是一個 .aidl 文件示例:/ IRemoteService.aidlpackage com.example.android;/ Declare any non-default types here with import statements/* Example service interface */interface IRe
9、moteService /* Request the process ID of this service, to do evil things with it. */ int getPid(); /* 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);只需
10、將您的 .aidl 文件保存在項目的 src/ 目錄內(nèi),當您開發(fā)應用時,SDK 工具會在項目的 gen/ 目錄中生成 IBinder 接口文件。生成的文件名與 .aidl 文件名一致,只是使用了 .java 擴展名(例如,IRemoteService.aidl 生成的文件名是 IRemoteService.java)。如果您使用 Android Studio,增量編譯幾乎會立即生成 Binder 類。 如果您不使用 Android Studio,則 Gradle 工具會在您下一次開發(fā)應用時生成 Binder 類 您應該在編寫完 .aidl 文件后立即用 gradle assembleDebug
11、 (或 gradle assembleRelease)編譯項目,以便您的代碼能夠鏈接到生成的類。1.2. 實現(xiàn)接口當您開發(fā)應用時,Android SDK 工具會生成一個以 .aidl 文件命名的 .java 接口文件。生成的接口包括一個名為 Stub 的子類,這個子類是其父接口(例如,YourInterface.Stub)的抽象實現(xiàn),用于聲明 .aidl 文件中的所有方法。注:Stub 還定義了幾個幫助程序方法,其中最引人關注的是 asInterface(),該方法帶 IBinder(通常便是傳遞給客戶端 onServiceConnected() 回調(diào)方法的參數(shù))并返回存根接口實例。 如需了解
12、如何進行這種轉(zhuǎn)換的更多詳細信息,請參見調(diào)用 IPC 方法一節(jié)。如需實現(xiàn) .aidl 生成的接口,請擴展生成的 Binder 接口(例如,YourInterface.Stub)并實現(xiàn)從 .aidl 文件繼承的方法。以下是一個使用匿名實例實現(xiàn)名為 IRemoteService 的接口(由以上 IRemoteService.aidl 示例定義)的示例:private final IRemoteService.Stub mBinder = new IRemoteService.Stub() public int getPid() return Process.myPid(); public void
13、basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) / Does nothing ;現(xiàn)在,mBinder 是 Stub 類的一個實例(一個 Binder),用于定義服務的 RPC 接口。 在下一步中,將向客戶端公開該實例,以便客戶端能與服務進行交互。在實現(xiàn) AIDL 接口時應注意遵守以下這幾個規(guī)則:由于不能保證在主線程上執(zhí)行傳入調(diào)用,因此您一開始就需要做好多線程處理準備,并將您的服務正確地編譯為線程安全服務。默認情況下,RPC 調(diào)用是同步調(diào)用。如果您明
14、知服務完成請求的時間不止幾毫秒,就不應該從 Activity 的主線程調(diào)用服務,因為這樣做可能會使應用掛起(Android 可能會顯示“Application is Not Responding”對話框) 您通常應該從客戶端內(nèi)的單獨線程調(diào)用服務。您引發(fā)的任何異常都不會回傳給調(diào)用方。1.2. 向客戶端公開該接口您為服務實現(xiàn)該接口后,就需要向客戶端公開該接口,以便客戶端進行綁定。 要為您的服務公開該接口,請擴展 Service 并實現(xiàn) onBind(),以返回一個類實例,這個類實現(xiàn)了生成的 Stub(見前文所述)。以下是一個向客戶端公開 IRemoteService 示例接口的服務示例。publi
15、c class RemoteService extends Service Override public void onCreate() super.onCreate(); Override public IBinder onBind(Intent intent) / Return the interface return mBinder; private final IRemoteService.Stub mBinder = new IRemoteService.Stub() public int getPid() return Process.myPid(); public void b
16、asicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) / Does nothing ;現(xiàn)在,當客戶端(如 Activity)調(diào)用 bindService() 以連接此服務時,客戶端的 onServiceConnected() 回調(diào)會接收服務的 onBind() 方法返回的 mBinder 實例??蛻舳诉€必須具有對 interface 類的訪問權限,因此如果客戶端和服務在不同的應用內(nèi),則客戶端的應用 src/ 目錄內(nèi)必須包含 .aidl 文件(它生成 and
17、roid.os.Binder 接口 為客戶端提供對 AIDL 方法的訪問權限)的副本。當客戶端在 onServiceConnected() 回調(diào)中收到 IBinder 時,它必須調(diào)用YourServiceInterface.Stub.asInterface(service) 以將返回的參數(shù)轉(zhuǎn)換成 YourServiceInterface 類型。例如:IRemoteService mIRemoteService;private ServiceConnection mConnection = new ServiceConnection() / Called when the connection
18、with the service is established public void onServiceConnected(ComponentName className, IBinder service) / Following the example above for an AIDL interface, / this gets an instance of the IRemoteInterface, which we can use to call on the service mIRemoteService = IRemoteService.Stub.asInterface(ser
19、vice); / Called when the connection with the service disconnects unexpectedly public void onServiceDisconnected(ComponentName className) Log.e(TAG, Service has unexpectedly disconnected); mIRemoteService = null; ;如需查看更多示例代碼,請參見 ApiDemos 中的 RemoteService.java 類。通過 IPC 傳遞對象通過 IPC 接口把某個類從一個進程發(fā)送到另一個進程是可
20、以實現(xiàn)的。 不過,您必須確保該類的代碼對 IPC 通道的另一端可用,并且該類必須支持 Parcelable 接口。支持 Parcelable 接口很重要,因為 Android 系統(tǒng)可通過它將對象分解成可編組到各進程的原語。如需創(chuàng)建支持 Parcelable 協(xié)議的類,您必須執(zhí)行以下操作:讓您的類實現(xiàn) Parcelable 接口。實現(xiàn) writeToParcel,它會獲取對象的當前狀態(tài)并將其寫入 Parcel。為您的類添加一個名為 CREATOR 的靜態(tài)字段,這個字段是一個實現(xiàn) Parcelable.Creator 接口的對象。最后,創(chuàng)建一個聲明可打包類的 .aidl 文件(按照下文 Rect.
21、aidl 文件所示步驟)。如果您使用的是自定義編譯進程,切勿在您的編譯中添加 .aidl 文件。 此 .aidl 文件與 C 語言中的頭文件類似,并未編譯。AIDL 在它生成的代碼中使用這些方法和字段將您的對象編組和取消編組。例如,以下這個 Rect.aidl 文件可創(chuàng)建一個可打包的 Rect 類:package android.graphics;/ Declare Rect so AIDL can find it and knows that it implements/ the parcelable protocol.parcelable Rect;以下示例展示了 Rect 類如何實現(xiàn) P
22、arcelable 協(xié)議。import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator CREATOR = newParcelable.Creator() public Rect createFromParcel(Parcel in) retu
23、rn new Rect(in); public Rect newArray(int size) return new Rectsize; ; public Rect() private Rect(Parcel in) readFromParcel(in); public void writeToParcel(Parcel out) out.writeInt(left); out.writeInt(top); out.writeInt(right); out.writeInt(bottom); public void readFromParcel(Parcel in) left = in.rea
24、dInt(); top = in.readInt(); right = in.readInt(); bottom = in.readInt(); Rect 類中的編組相當簡單??匆豢?Parcel 上的其他方法,了解您可以向 Parcel 寫入哪些其他類型的值。警告:別忘記從其他進程接收數(shù)據(jù)的安全影響。 在本例中,Rect 從 Parcel 讀取四個數(shù)字,但要由您來確保無論調(diào)用方目的為何這些數(shù)字都在相應的可接受值范圍內(nèi)。 如需了解有關如何防止應用受到惡意軟件侵害、保證應用安全的更多信息,請參見安全與權限。調(diào)用 IPC 方法調(diào)用類必須執(zhí)行以下步驟,才能調(diào)用使用 AIDL 定義的遠程接口:在項目
25、src/ 目錄中加入 .aidl 文件。聲明一個 IBinder 接口實例(基于 AIDL 生成)。實現(xiàn) ServiceConnection。調(diào)用 linkandroid.content.Context#bindService(android.content.Intent,android.content.ServiceConnection,int) Context.bindService(),以傳入您的 ServiceConnection 實現(xiàn)。在您的 onServiceConnected() 實現(xiàn)中,您將收到一個 IBinder 實例(名為 service)。調(diào)用 YourInterface
26、Name.Stub.asInterface(IBinder)service),以將返回的參數(shù)轉(zhuǎn)換為 YourInterface 類型。調(diào)用您在接口上定義的方法。您應該始終捕獲 DeadObjectException 異常,它們是在連接中斷時引發(fā)的;這將是遠程方法引發(fā)的唯一異常。如需斷開連接,請使用您的接口實例調(diào)用 linkandroid.content.Context#unbindService(android.content.ServiceConnection) Context.unbindService()。有關調(diào)用 IPC 服務的幾點說明:對象是跨進程計數(shù)的引用。您可以將匿名對象作為方法
27、參數(shù)發(fā)送。如需了解有關綁定到服務的詳細信息,請閱讀綁定服務文檔。以下這些示例代碼摘自 ApiDemos 項目的遠程服務示例代碼,展示了如何調(diào)用 AIDL 創(chuàng)建的服務。public static class Binding extends Activity /* The primary interface we will be calling on the service. */ IRemoteService mService = null; /* Another interface we use on the service. */ ISecondary mSecondaryService =
28、 null; Button mKillButton; TextView mCallbackText; private boolean mIsBound; /* * Standard initialization of this activity. Set up the UI, then wait * for the user to poke it before doing anything. */ Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); set
29、ContentView(R.layout.remote_service_binding); / Watch for button clicks. Button button = (Button)findViewById(R.id.bind); button.setOnClickListener(mBindListener); button = (Button)findViewById(R.id.unbind); button.setOnClickListener(mUnbindListener); mKillButton = (Button)findViewById(R.id.kill); m
30、KillButton.setOnClickListener(mKillListener); mKillButton.setEnabled(false); mCallbackText = (TextView)findViewById(R.id.callback); mCallbackText.setText(Not attached.); /* * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnectio
31、n() public void onServiceConnected(ComponentName className, IBinder service) / This is called when the connection with the service has been / established, giving us the service object we can use to / interact with the service. We are communicating with our / service through an IDL interface, so get
32、a client-side / representation of that from the raw service object. mService = IRemoteService.Stub.asInterface(service); mKillButton.setEnabled(true); mCallbackText.setText(Attached.); / We want to monitor the service for as long as we are / connected to it. try mService.registerCallback(mCallback);
33、 catch (RemoteException e) / In this case the service has crashed before we could even / do anything with it; we can count on soon being / disconnected (and then reconnected if it can be restarted) / so there is no need to do anything here. / As part of the sample, tell the user what happened. Toast
34、.makeText(Binding.this, R.string.remote_service_connected, Toast.LENGTH_SHORT).show(); public void onServiceDisconnected(ComponentName className) / This is called when the connection with the service has been / unexpectedly disconnected - that is, its process crashed. mService = null; mKillButton.se
35、tEnabled(false); mCallbackText.setText(Disconnected.); / As part of the sample, tell the user what happened. Toast.makeText(Binding.this, R.string.remote_service_disconnected, Toast.LENGTH_SHORT).show(); ; /* * Class for interacting with the secondary interface of the service. */ private ServiceConn
36、ection mSecondaryConnection = new ServiceConnection() public void onServiceConnected(ComponentName className, IBinder service) / Connecting to a secondary interface is the same as any / other interface. mSecondaryService = ISecondary.Stub.asInterface(service); mKillButton.setEnabled(true); public vo
37、id onServiceDisconnected(ComponentName className) mSecondaryService = null; mKillButton.setEnabled(false); ; private OnClickListener mBindListener = new OnClickListener() public void onClick(View v) / Establish a couple connections with the service, binding / by interface names. This allows other ap
38、plications to be / installed that replace the remote service by implementing / the same interface. Intent intent = new Intent(Binding.this, RemoteService.class); intent.setAction(IRemoteService.class.getName(); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); intent.setAction(ISecondary.c
39、lass.getName(); bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE); mIsBound = true; mCallbackText.setText(Binding.); ; private OnClickListener mUnbindListener = new OnClickListener() public void onClick(View v) if (mIsBound) / If we have received the service, and hence registered w
40、ith / it, then now is the time to unregister. if (mService != null) try mService.unregisterCallback(mCallback); catch (RemoteException e) / There is nothing special we need to do if the service / has crashed. / Detach our existing connection. unbindService(mConnection); unbindService(mSecondaryConne
41、ction); mKillButton.setEnabled(false); mIsBound = false; mCallbackText.setText(Unbinding.); ; private OnClickListener mKillListener = new OnClickListener() public void onClick(View v) / To kill the process hosting our service, we need to know its / PID. Conveniently our service has a call that will
42、return / to us that information. if (mSecondaryService != null) try int pid = mSecondaryService.getPid(); / Note that, though this API allows us to request to / kill any process based on its PID, the kernel will / still impose standard restrictions on which PIDs you / are actually able to kill. Typically this means only / the
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 鍍銅纖維施工方案(3篇)
- 煤棚電路施工方案(3篇)
- 職工公寓活動方案策劃(3篇)
- 6.18活動策劃方案資質(zhì)(3篇)
- 天車噴漆施工方案(3篇)
- 電桿卡盤施工方案(3篇)
- 企業(yè)設備管理與維護指南(標準版)
- 裝飾公司銷售營銷培訓
- 水泥行業(yè)職業(yè)危害培訓
- 2025年大學大二(國際貿(mào)易)國際貿(mào)易實務試題及答案
- 菏澤風電項目可行性研究報告
- T/CCMA 0114-2021履帶式升降工作平臺
- DB32T 5124.1-2025 臨床護理技術規(guī)范 第1部分:成人危重癥患者目標溫度管理
- 專題13 三角函數(shù)中的最值模型之胡不歸模型(原卷版)
- 職高高二語文試卷及答案分析
- 2025屆江蘇省南通市高三下學期3月二?;瘜W試題(含答案)
- 班主任安全管理分享會
- 消防救援預防職務犯罪
- 畢業(yè)論文答辯的技巧有哪些
- 酒店安全風險分級管控和隱患排查雙重預防
- 2018年風電行業(yè)事故錦集
評論
0/150
提交評論