android處理序間通訊:使用AIDL

來源:互聯網
上載者:User

      歡迎閱讀本文,你能關注本文,你知道你需要處理序間通訊、需要AIDL(以及Binder),那麼可以預設你對這些概念已經有了一些瞭解,你(大致)知道它們是什麼,它們有什麼用,所以為了節約大家的眼力和時間,在此我不複製粘貼網上泛濫的部落格或者翻譯冗長的android文檔。

      關於AIDL的介紹在文檔:docs/guide/developing/tools/aidl.html

      關於IBinder的介紹在文檔:docs/reference/android/os/IBinder.html

      以及Binder:docs/reference/android/os/Binder.html

      在後文中,我將以我自己的理解向你介紹相關的概念。以我目前粗淺的經驗,應用程式使用AIDL的地方,幾乎都和Service有關,所以你也需要知道一些關於Service的知識。日後得閑我也會繼續寫一些關於Service的貼。

      本文將以一個例子來和你分享使用AIDL的基礎技能,這個例子裡有:

1、一個類mAIDLActivity,繼承Activity。裡面有三個按鈕,text分別為StartService,StopService,CallbackTest。

2、一個類mAIDLService,繼承Service。為了充分展示ADIL的功能,它做以下工作:當使用者點擊CallbackTest按鈕時,從mAIDLActivity調用mAIDLService中的Stub

對象的一個方法invokCallBack(),而這個方法又會調用mAIDLActivity中Stub

對象的一個方法performAction(),這個方法在螢幕上顯示一個toast。沒什麼意義,只是展示一下AIDL如何使用。

3、兩個AIDL檔案:forService.aidl和forActivity.aidl。對應名字,在Service和Activity中分別有對象需要用到它們定義的介面。

4、相關XML檔案,略過。關於manifest中Service的文法,見docs/guide/topics/manifest/service-element.html。你也可以簡單地在<application></application>中加入

     <service android:name=".mAIDLService" android:process=":remote"> </service>

開發環境為Eclipse。

揀重要的先說,來看看aidl檔案的內容:

檔案:forActivity.aidl

package com.styleflying.AIDL;<br />interface forActivity {<br />void performAction();<br />}
 

檔案:forService.aidl

package com.styleflying.AIDL;<br />import com.styleflying.AIDL.forActivity;<br />interface forService {<br />void registerTestCall(forActivity cb);<br />void invokCallBack();<br />}
 

這兩個檔案和Java檔案放置的地方一樣,看包名。

在Eclipse中它們將被自動編譯為forActivity.java和forService.java,它們存放在gen目錄下。為了方便手頭無法演練的讀者,代碼貼上,不用細看。

檔案forActivity.java:

/*<br /> * This file is auto-generated. DO NOT MODIFY.<br /> * Original file: D://workspace//AIDLTest//src//com//styleflying//AIDL//forActivity.aidl<br /> */<br />package com.styleflying.AIDL;<br />import java.lang.String;<br />import android.os.RemoteException;<br />import android.os.IBinder;<br />import android.os.IInterface;<br />import android.os.Binder;<br />import android.os.Parcel;<br />public interface forActivity extends android.os.IInterface<br />{<br />/** Local-side IPC implementation stub class. */<br />public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forActivity<br />{<br />private static final java.lang.String DESCRIPTOR = "com.styleflying.AIDL.forActivity";<br />/** Construct the stub at attach it to the interface. */<br />public Stub()<br />{<br />this.attachInterface(this, DESCRIPTOR);<br />}<br />/**<br /> * Cast an IBinder object into an forActivity interface,<br /> * generating a proxy if needed.<br /> */<br />public static com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)<br />{<br />if ((obj==null)) {<br />return null;<br />}<br />android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);<br />if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forActivity))) {<br />return ((com.styleflying.AIDL.forActivity)iin);<br />}<br />return new com.styleflying.AIDL.forActivity.Stub.Proxy(obj);<br />}<br />public android.os.IBinder asBinder()<br />{<br />return this;<br />}<br />@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException<br />{<br />switch (code)<br />{<br />case INTERFACE_TRANSACTION:<br />{<br />reply.writeString(DESCRIPTOR);<br />return true;<br />}<br />case TRANSACTION_performAction:<br />{<br />data.enforceInterface(DESCRIPTOR);<br />this.performAction();<br />reply.writeNoException();<br />return true;<br />}<br />}<br />return super.onTransact(code, data, reply, flags);<br />}<br />private static class Proxy implements com.styleflying.AIDL.forActivity<br />{<br />private android.os.IBinder mRemote;<br />Proxy(android.os.IBinder remote)<br />{<br />mRemote = remote;<br />}<br />public android.os.IBinder asBinder()<br />{<br />return mRemote;<br />}<br />public java.lang.String getInterfaceDescriptor()<br />{<br />return DESCRIPTOR;<br />}<br />public void performAction() throws android.os.RemoteException<br />{<br />android.os.Parcel _data = android.os.Parcel.obtain();<br />android.os.Parcel _reply = android.os.Parcel.obtain();<br />try {<br />_data.writeInterfaceToken(DESCRIPTOR);<br />mRemote.transact(Stub.TRANSACTION_performAction, _data, _reply, 0);<br />_reply.readException();<br />}<br />finally {<br />_reply.recycle();<br />_data.recycle();<br />}<br />}<br />}<br />static final int TRANSACTION_performAction = (IBinder.FIRST_CALL_TRANSACTION + 0);<br />}<br />public void performAction() throws android.os.RemoteException;<br />}<br />

檔案forService.java:

/*<br /> * This file is auto-generated. DO NOT MODIFY.<br /> * Original file: D://workspace//AIDLTest//src//com//styleflying//AIDL//forService.aidl<br /> */<br />package com.styleflying.AIDL;<br />import java.lang.String;<br />import android.os.RemoteException;<br />import android.os.IBinder;<br />import android.os.IInterface;<br />import android.os.Binder;<br />import android.os.Parcel;<br />public interface forService extends android.os.IInterface<br />{<br />/** Local-side IPC implementation stub class. */<br />public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forService<br />{<br />private static final java.lang.String DESCRIPTOR = "com.styleflying.AIDL.forService";<br />/** Construct the stub at attach it to the interface. */<br />public Stub()<br />{<br />this.attachInterface(this, DESCRIPTOR);<br />}<br />/**<br /> * Cast an IBinder object into an forService interface,<br /> * generating a proxy if needed.<br /> */<br />public static com.styleflying.AIDL.forService asInterface(android.os.IBinder obj)<br />{<br />if ((obj==null)) {<br />return null;<br />}<br />android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);<br />if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forService))) {<br />return ((com.styleflying.AIDL.forService)iin);<br />}<br />return new com.styleflying.AIDL.forService.Stub.Proxy(obj);<br />}<br />public android.os.IBinder asBinder()<br />{<br />return this;<br />}<br />@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException<br />{<br />switch (code)<br />{<br />case INTERFACE_TRANSACTION:<br />{<br />reply.writeString(DESCRIPTOR);<br />return true;<br />}<br />case TRANSACTION_registerTestCall:<br />{<br />data.enforceInterface(DESCRIPTOR);<br />com.styleflying.AIDL.forActivity _arg0;<br />_arg0 = com.styleflying.AIDL.forActivity.Stub.asInterface(data.readStrongBinder());<br />this.registerTestCall(_arg0);<br />reply.writeNoException();<br />return true;<br />}<br />case TRANSACTION_invokCallBack:<br />{<br />data.enforceInterface(DESCRIPTOR);<br />this.invokCallBack();<br />reply.writeNoException();<br />return true;<br />}<br />}<br />return super.onTransact(code, data, reply, flags);<br />}<br />private static class Proxy implements com.styleflying.AIDL.forService<br />{<br />private android.os.IBinder mRemote;<br />Proxy(android.os.IBinder remote)<br />{<br />mRemote = remote;<br />}<br />public android.os.IBinder asBinder()<br />{<br />return mRemote;<br />}<br />public java.lang.String getInterfaceDescriptor()<br />{<br />return DESCRIPTOR;<br />}<br />public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException<br />{<br />android.os.Parcel _data = android.os.Parcel.obtain();<br />android.os.Parcel _reply = android.os.Parcel.obtain();<br />try {<br />_data.writeInterfaceToken(DESCRIPTOR);<br />_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));<br />mRemote.transact(Stub.TRANSACTION_registerTestCall, _data, _reply, 0);<br />_reply.readException();<br />}<br />finally {<br />_reply.recycle();<br />_data.recycle();<br />}<br />}<br />public void invokCallBack() throws android.os.RemoteException<br />{<br />android.os.Parcel _data = android.os.Parcel.obtain();<br />android.os.Parcel _reply = android.os.Parcel.obtain();<br />try {<br />_data.writeInterfaceToken(DESCRIPTOR);<br />mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);<br />_reply.readException();<br />}<br />finally {<br />_reply.recycle();<br />_data.recycle();<br />}<br />}<br />}<br />static final int TRANSACTION_registerTestCall = (IBinder.FIRST_CALL_TRANSACTION + 0);<br />static final int TRANSACTION_invokCallBack = (IBinder.FIRST_CALL_TRANSACTION + 1);<br />}<br />public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException;<br />public void invokCallBack() throws android.os.RemoteException;<br />}<br />

兩段代碼差不多,前面基本一樣,從後面看,最後跟著我們在AIDL中自訂的方法,沒有實現。兩個檔案各定義一個了介面,這兩個介面分別會在Activity和Service中使用,在那裡我們將實現自訂的方法。兩個介面中都定義了一個抽象類別Stub,實現所在的介面。Stub中又有一個類Proxy。Stub中有一個static的asInterface()方法,裡面有很多return語句,在mAIDLActivity中調用它時,它返回一個新建立的內部類Proxy對象。

這個Stub對我們來說很有用,它繼承了Binder。Binder有什麼用呢?一個類,繼承了Binder,那麼它的對象就可以被遠端進程使用了(前提是遠程進程擷取了這個類的對象【對象的引用】,至於如如何獲得看下文),在本例中就是說,如果一個Service中有一個繼承了Stub的類的對象,那麼這個對象中的方法就可以在Activity中使用,對Activity也是這樣。至於Binder的細節,網上有很多貼介紹,看不明白也不影響我們完成這個例子。

再看mAIDLActivity.java:

package com.styleflying.AIDL;<br />import android.app.Activity;<br />import android.content.ComponentName;<br />import android.content.Context;<br />import android.content.Intent;<br />import android.content.ServiceConnection;<br />import android.os.Bundle;<br />import android.os.IBinder;<br />import android.os.RemoteException;<br />import android.util.Log;<br />import android.view.View;<br />import android.view.View.OnClickListener;<br />import android.widget.Button;<br />import android.widget.Toast;<br />public class mAIDLActivity extends Activity {<br />private static final String TAG = "AIDLActivity";<br />private Button btnOk;<br /> private Button btnCancel;<br /> private Button btnCallBack;</p><p> private void Log(String str) {<br /> Log.d(TAG, "------ " + str + "------");<br /> }</p><p> private forActivity mCallback = new forActivity.Stub() {<br />public void performAction() throws RemoteException<br />{<br />Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();<br />}<br />};</p><p>forService mService;<br />private ServiceConnection mConnection = new ServiceConnection() {<br />public void onServiceConnected(ComponentName className,<br />IBinder service) {<br />mService = forService.Stub.asInterface(service);<br />try {<br />mService.registerTestCall(mCallback);}<br />catch (RemoteException e) {</p><p>}<br />}<br />public void onServiceDisconnected(ComponentName className) {<br />Log("disconnect service");<br />mService = null;<br />}<br />};<br /> @Override<br /> public void onCreate(Bundle icicle) {<br /> super.onCreate(icicle);<br /> setContentView(R.layout.main);<br /> btnOk = (Button)findViewById(R.id.btn_ok);<br /> btnCancel = (Button)findViewById(R.id.btn_cancel);<br /> btnCallBack = (Button)findViewById(R.id.btn_callback);<br /> btnOk.setOnClickListener(new OnClickListener() {<br /> public void onClick(View v) {<br /> Bundle args = new Bundle();<br /> Intent intent = new Intent(mAIDLActivity.this, mAIDLService.class);<br /> intent.putExtras(args);<br /> bindService(intent, mConnection, Context.BIND_AUTO_CREATE);<br /> startService(intent);<br /> }<br /> });<br /> btnCancel.setOnClickListener(new OnClickListener() {<br /> public void onClick(View v) {<br /> unbindService(mConnection);<br /> //stopService(intent);<br /> }<br /> });<br /> btnCallBack.setOnClickListener(new OnClickListener() {</p><p>@Override<br />public void onClick(View v)<br />{<br />try<br />{<br />mService.invokCallBack();<br />} catch (RemoteException e)<br />{<br />// TODO Auto-generated catch block<br />e.printStackTrace();<br />}<br />}<br />});<br /> }<br />}

 

很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);給mService賦值了,這個mService是一個forService,而service是onServiceConnected()傳進來的參數,onServiceConnected()會在串連Service的時候被系統調用,這個service參數的值來自哪裡呢?看mAIDLService.java:

package com.styleflying.AIDL;<br />import android.app.Service;<br />import android.content.Intent;<br />import android.os.IBinder;<br />import android.os.RemoteCallbackList;<br />import android.os.RemoteException;<br />import android.util.Log;<br />public class mAIDLService extends Service {<br /> private static final String TAG = "AIDLService";<br /> private forActivity callback;<br /> private void Log(String str) {<br /> Log.d(TAG, "------ " + str + "------");<br /> }<br /> @Override<br /> public void onCreate() {<br /> Log("service create");<br /> }<br /> @Override<br /> public void onStart(Intent intent, int startId) {<br /> Log("service start id=" + startId);<br /> }</p><p> @Override<br /> public IBinder onBind(Intent t) {<br /> Log("service on bind");<br /> return mBinder;<br /> }<br /> @Override<br /> public void onDestroy() {<br /> Log("service on destroy");<br /> super.onDestroy();<br /> }<br /> @Override<br /> public boolean onUnbind(Intent intent) {<br /> Log("service on unbind");<br /> return super.onUnbind(intent);<br /> }<br /> public void onRebind(Intent intent) {<br /> Log("service on rebind");<br /> super.onRebind(intent);<br /> }<br /> private final forService.Stub mBinder = new forService.Stub() {<br />@Override<br />public void invokCallBack() throws RemoteException<br />{<br />callback.performAction();</p><p>}<br />@Override<br />public void registerTestCall(forActivity cb) throws RemoteException<br />{<br />callback = cb;</p><p>}</p><p> };<br />}

注意onBind(),它的傳回型別為IBinder,返回了一個mBinder,看看mBinder的定義:

    private final forService.Stub mBinder = new forService.Stub() {

        @Override

        public void invokCallBack() throws RemoteException

        {

            callback.performAction();

         }

        @Override

        public void registerTestCall(forActivity cb) throws RemoteException

        {

            callback = cb;

        }

       };

它是實現了我們在AIDL中定義的方法,這個mBinder最終返回給了mAIDLActivity中的mService,於是在mAIDLActivity中可以使用mBinder中的方法了。在mAIDLActivity中也有一個類似mBinder的對象,看看定義:   

        private forActivity mCallback = new forActivity.Stub()

    {

        public void performAction() throws RemoteException

        {

            Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show();

        }

      };

我們要在介面上顯示一個toast,就是在這裡實現的。這個對象,在mConnection的onServiceConnected()被調用時,通過調用mService(也就是遠端mAIDLService中的mBinder)的registerTestCall(),傳遞給了mAIDLService,於是在mAIDLService中可以調用performAction()了。

很囉嗦,只為了能把這個細節說清楚。請大家認真看,我盡量避免錯別字、混亂的大小寫和邏輯不清的文法,相信你會看明白。是不是很簡單?再囉嗦一下,做一個大致總結,我們使用AIDL是要做什麼呢:

讓Acticity(或者說一個進程/一個類?)和Service(或者說遠端進程/遠端類/對象?)擷取對方的一個Stub對象,這個對象在定義時實現了我們在AIDL中定義的方法,於是這些遠程對象中的方法可以在本地使用了。如果這種使用(通訊)是單向的,比如只是Activity需要通知Service做什麼,那麼只要Service中有一個Stub對象,並且傳給Acticity就夠了。

至於如何獲得遠端Stub,參看上面的代碼,看mConnection、registerTestCall、onRebind,它們展示了一種方法。

另外,有時候我們可能在一個類中有多個Stub對象,它們都要給遠程互動的類的執行個體,這個時候可以考慮使用RemoteCallbackList<>(docs/reference/android/os/RemoteCallbackList.html)。

歡迎閱讀、收藏本文。例子隨手寫的,功能只在示範AIDL的使用。您可以轉載本文,但請勿盲目亂貼。不是我小氣,我不權威,我怕它被貼到泛濫,以訛傳訛,害了人。

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.