android进程间通信:使用AIDL
android 的binder其實是基于 openbinder實現的,openbinder的地址:http://www.angryredplanet.com/~hackbod/openbinder/docs/html/
http://blog.csdn.net/saintswordsman/article/details/5130947
?
歡迎閱讀本文,你能關注本文,你知道你需要進程間通信、需要AIDL(以及Binder),那么可以默認你對這些概念已經有了一些了解,你(大致) 知道它們是什么,它們有什么用,所以為了節(jié)約大家的眼力和時間,在此我不復制粘貼網上泛濫的博客或者翻譯冗長的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的知識。日后得閑我也會繼續(xù)寫一些關于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>
開發(fā)環(huán)境為Eclipse。
揀重要的先說,來看看aidl文件的內容:
文件:forActivity.aidl
package com.styleflying.AIDL; interface forActivity { void performAction(); }文件:forService.aidl
package com.styleflying.AIDL; import com.styleflying.AIDL.forActivity; interface forService { void registerTestCall(forActivity cb); void invokCallBack(); }這兩個文件和Java文件放置的地方一樣,看包名。
在Eclipse中它們將被自動編譯為forActivity.java和forService.java,它們存放在gen目錄下。為了方便手頭無法演練的讀者,代碼不貼,不用細看。
?
再看mAIDLActivity.java:
package com.styleflying.AIDL; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class mAIDLActivity extends Activity { private static final String TAG = "AIDLActivity"; private Button btnOk; private Button btnCancel; private Button btnCallBack; private void Log(String str) { Log.d(TAG, "------ " + str + "------"); } private forActivity mCallback = new forActivity.Stub() { public void performAction() throws RemoteException { Toast.makeText(mAIDLActivity.this, "this toast is called from service", 1).show(); } }; forService mService; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mService = forService.Stub.asInterface(service); try { mService.registerTestCall(mCallback);} catch (RemoteException e) { } } public void onServiceDisconnected(ComponentName className) { Log("disconnect service"); mService = null; } }; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); btnOk = (Button)findViewById(R.id.btn_ok); btnCancel = (Button)findViewById(R.id.btn_cancel); btnCallBack = (Button)findViewById(R.id.btn_callback); btnOk.setOnClickListener(new OnClickListener() { public void onClick(View v) { Bundle args = new Bundle(); Intent intent = new Intent(mAIDLActivity.this, mAIDLService.class); intent.putExtras(args); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); startService(intent); } }); btnCancel.setOnClickListener(new OnClickListener() { public void onClick(View v) { unbindService(mConnection); //stopService(intent); } }); btnCallBack.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { mService.invokCallBack(); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } }很短,相信大家很容易看明白。注意mConnection,它的onServiceConnected()中有一句mService = forService.Stub.asInterface(service);給mService賦值了,這個mService是一個 forService,而service是onServiceConnected()傳進來的參數,onServiceConnected()會在連接 Service的時候被系統(tǒng)調用,這個service參數的值來自哪里呢?
看mAIDLService.java:
package com.styleflying.AIDL; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Log; public class mAIDLService extends Service { private static final String TAG = "AIDLService"; private forActivity callback; private void Log(String str) { Log.d(TAG, "------ " + str + "------"); } @Override public void onCreate() { Log("service create"); } @Override public void onStart(Intent intent, int startId) { Log("service start id=" + startId); } @Override public IBinder onBind(Intent t) { Log("service on bind"); return mBinder; } @Override public void onDestroy() { Log("service on destroy"); super.onDestroy(); } @Override public boolean onUnbind(Intent intent) { Log("service on unbind"); return super.onUnbind(intent); } public void onRebind(Intent intent) { Log("service on rebind"); super.onRebind(intent); } 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; } }; }注意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()了。
很啰嗦,只為了能把這個細節(jié)說清楚。請大家認真看,我盡量避免錯別字、混亂的大小寫和邏輯不清的語法,相信你會看明白。是不是很簡單?再啰嗦一下,做一個大致總結,我們使用AIDL是要做什么呢:
讓Acticity(或者說一個進程/一個類?)和Service(或者說遠端進程/遠端類/對象?)獲取對方的一個Stub對象,這個對象在定義 時實現了我們在AIDL中定義的方法,于是這些遠程對象中的方法可以在本地使用了。如果這種使用(通信)是單向的,比如只是Activity需要通知 Service做什么,那么只要Service中有一個Stub對象,并且傳給Acticity就夠了。
至于如何獲得遠程的Stub,參看上面的代碼,看mConnection、registerTestCall、onRebind,它們展示了一種方法。
另外,有時候我們可能在一個類中有多個Stub對象,它們都要給遠程交互的類的實例,這個時候可以考慮使用RemoteCallbackList<>(docs/reference/android/os/RemoteCallbackList.html)。
?
=============================
Service的生命周期?Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy?
我們有兩種方式啟動一個Service,他們對Service生命周期的影響是不一樣的。
1 通過startService?
? ? Service會經歷 onCreate -> onStart?
? ?stopService的時候直接onDestroy?
? ?如果是調用者(TestServiceHolder)自己直接退出而沒有調用stopService的?
? ?話,Service會一直在后臺運行。?
? ?下次TestServiceHolder再起來可以stopService。
??2 通過bindService? ??
? ? Service只會運行onCreate, 這個時候 TestServiceHolder 和TestService綁定在一起?
? ?TestServiceHolder 退出了,Srevice就會調用onUnbind->onDestroyed?
? ?所謂綁定在一起就共存亡了。?
那有同學問了,要是這幾個方法交織在一起的話,會出現什么情況呢??
一 個原則是Service的onCreate的方法只會被調用一次,就是你無論多少次的startService又 bindService,Service只被創(chuàng)建一次。如果先是bind了,那么start的時候就直接運行Service的onStart方法,如果先 是start,那么bind的時候就直接運行onBind方法。如果你先bind上了,就stop不掉了,對啊,就是stopService不好使了,只 能先UnbindService, 再StopService,所以是先start還是先bind行為是有區(qū)別的。?
服 務不能自己運行,需要通過調用Context.startService()或Context.bindService()方法啟動服務。這兩個方法都可 以啟動Service,但是它們的使用場合有所不同。使用startService()方法啟用服務,調用者與服務之間沒有關連,即使調用者退出了,服務 仍然運行。使用bindService()方法啟用服務,調用者與服務綁定在了一起,調用者一旦退出,服務也就終止,大有“不求同時生,必須同時死”的特 點。
如 果打算采用Context.startService()方法啟動服務,在服務未被創(chuàng)建時,系統(tǒng)會先調用服務的onCreate()方法,接著調用 onStart()方法。如果調用startService()方法前服務已經被創(chuàng)建,多次調用startService()方法并不會導致多次創(chuàng)建服 務,但會導致多次調用onStart()方法。采用startService()方法啟動的服務,只能調用Context.stopService()方 法結束服務,服務結束時會調用onDestroy()方法。
如 果打算采用Context.bindService()方法啟動服務,在服務未被創(chuàng)建時,系統(tǒng)會先調用服務的onCreate()方法,接著調用 onBind()方法。這個時候調用者和服務綁定在一起,調用者退出了,系統(tǒng)就會先調用服務的onUnbind()方法,接著調用onDestroy() 方法。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法并不會導致多次創(chuàng)建服務及綁定(也就是說 onCreate()和onBind()方法并不會被多次調用)。如果調用者希望與正在綁定的服務解除綁定,可以調用unbindService()方 法,調用該方法也會導致系統(tǒng)調用服務的onUnbind()-->onDestroy()方法.
?
你可以綁定一個已經通過startService()方法啟動的服務。例如:一 個后臺播放音樂服務可以通過startService(intend)對象來播放音樂。可能用戶在播放過程中要執(zhí)行一些操作比如獲取歌曲的一些信息,此時 activity可以通過調用bindServices()方法與Service建立連接。這種情況下,unbindService() 及 stopServices()方法實際上不會停止服務,直到最后一次的綁定被關閉。
?
================================================================
?
Android之進程間傳遞自定義類型參數
【0】AIDL默認支持的類型包話java基本類型(int、long、boolean等)和(String、List、Map、CharSequence)(好像數組也可以,只要實現了Parcelable接口),如果要傳遞自定義的類型該如何實現呢?
要傳遞自定義類型,首先要讓自定義類型支持parcelable協(xié)議,實現步驟如下:
1>自定義類型必須實現Parcelable接口,并且實現Parcelable接口的public void writeToParcel(Parcel dest, int flags)方法 。
2>自定義類型中必須含有一個名稱為CREATOR的靜態(tài)成員,該成員對象要求實現Parcelable.Creator接口及其方法。
3>創(chuàng)建一個aidl文件聲明你的自定義類型。
Parcelable接口的作用:實現了Parcelable接口的實例可以將自身的狀態(tài)信息(狀態(tài)信息通常指的是各成員變量的值)寫入Parcel,也可以從Parcel中恢復其狀態(tài)。 Parcel用來完成數據的序列化傳遞。?
【1】進程間傳遞自定義類型的實現過程?
1> 創(chuàng)建自定義類型,并實現Parcelable接口,使其支持parcelable協(xié)議。如:在com.hoo.domin創(chuàng)建Person.java:
2> 在自定義類型所在包下創(chuàng)建一個aidl文件對自定義類型進行聲明,文件的名稱與自定義類型同名。
package com.hoo.domin
parcelable Person;?
3> 在接口aidl文件中使用自定義類型,需要使用import顯式導入,本例在com.hoo.aidl包下創(chuàng)建IPersonService.aidl文件,內容如下:
4> 在實現aidl文件生成的接口(本例是IPersonService),但并非直接實現接口,而是通過繼承接口的Stub來實現(Stub抽象類內部實現了aidl接口),并且實現接口方法的代碼。內容如下:
5> 創(chuàng)建一個Service(服務),在服務的onBind(Intent intent)方法中返回實現了aidl接口的對象(本例是ServiceBinder)。內容如下:
其他應用可以通過隱式意圖訪問服務,意圖的動作可以自定義,AndroidManifest.xml配置代碼如下:
?
總結
以上是生活随笔為你收集整理的android进程间通信:使用AIDL的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1.1-1.5-vim编辑器
- 下一篇: JQuery Tree 树形结构插件 z