新聞中心
在 Android 世界里,默認(rèn)的每個(gè) APP 是一個(gè)單獨(dú)的進(jìn)程。其實(shí)這樣的描述是不嚴(yán)格的,因?yàn)樵蹅円芯?Android 的進(jìn)程間通信,肯定出了和其他的 APP 通信外,還可能和同一個(gè) APP 下的其他進(jìn)程通信,下面為大家詳細(xì)講解一下Android進(jìn)程通信。

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專(zhuān)注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、重慶小程序開(kāi)發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶(hù)創(chuàng)新互聯(lián)還提供了山城免費(fèi)建站歡迎大家使用!
進(jìn)程間通信(ipc)
IPC方法總是產(chǎn)生客戶(hù)/服務(wù)端模式的調(diào)用,也即是客戶(hù)端組件(Activity/Service)持有服務(wù)端Service的組件,只能是客戶(hù)端主動(dòng)調(diào)用服務(wù)端的方法,服務(wù)端無(wú)法反過(guò)來(lái)調(diào)用客戶(hù)端的方法,因?yàn)镮PC的另一端Service無(wú)法獲取客戶(hù)端的對(duì)象。
binder
Binder 是一種進(jìn)程間通信機(jī)制。安卓中跨進(jìn)程通訊就是通過(guò)binder。當(dāng)綁定服務(wù)的時(shí)候會(huì)返回一個(gè)binder對(duì)象,然后通過(guò)他進(jìn)行多進(jìn)程間的通信。Binder只需要一次數(shù)據(jù)拷貝,性能上僅次于共享內(nèi)存。
在 Android 系統(tǒng)中,這個(gè)運(yùn)行在內(nèi)核空間,負(fù)責(zé)各個(gè)用戶(hù)進(jìn)程通過(guò) Binder 實(shí)現(xiàn)通信的內(nèi)核模塊就叫 Binder 驅(qū)動(dòng)(Binder Dirver)。
Binder IPC 機(jī)制中涉及到的內(nèi)存映射通過(guò) mmap() 來(lái)實(shí)現(xiàn),mmap() 是操作系統(tǒng)中一種內(nèi)存映射的方法。內(nèi)存映射簡(jiǎn)單的講就是將用戶(hù)空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間。映射關(guān)系建立后,用戶(hù)對(duì)這塊內(nèi)存區(qū)域的修改可以直接反應(yīng)到內(nèi)核空間;反之內(nèi)核空間對(duì)這段區(qū)域的修改也能直接反應(yīng)到用戶(hù)空間。
內(nèi)存映射能減少數(shù)據(jù)拷貝次數(shù),實(shí)現(xiàn)用戶(hù)空間和內(nèi)核空間的高效互動(dòng)。兩個(gè)空間各自的修改能直接反映在映射的內(nèi)存區(qū)域,從而被對(duì)方空間及時(shí)感知。也正因?yàn)槿绱?,?nèi)存映射能夠提供對(duì)進(jìn)程間通信的支持。
Binder IPC 正是基于內(nèi)存映射(mmap)來(lái)實(shí)現(xiàn)的
Binder 通信中的代理模式
我們已經(jīng)解釋清楚 Client、Server 借助 Binder 驅(qū)動(dòng)完成跨進(jìn)程通信的實(shí)現(xiàn)機(jī)制了,但是還有個(gè)問(wèn)題會(huì)讓我們困惑。A 進(jìn)程想要 B 進(jìn)程中某個(gè)對(duì)象(object)是如何實(shí)現(xiàn)的呢?畢竟它們分屬不同的進(jìn)程,A 進(jìn)程 沒(méi)法直接使用 B 進(jìn)程中的 object。
前面我們介紹過(guò)跨進(jìn)程通信的過(guò)程都有 Binder 驅(qū)動(dòng)的參與,因此在數(shù)據(jù)流經(jīng) Binder 驅(qū)動(dòng)的時(shí)候驅(qū)動(dòng)會(huì)對(duì)數(shù)據(jù)做一層轉(zhuǎn)換。當(dāng) A 進(jìn)程想要獲取 B 進(jìn)程中的 object 時(shí),驅(qū)動(dòng)并不會(huì)真的把 object 返回給 A,而是返回了一個(gè)跟 object 看起來(lái)一模一樣的代理對(duì)象 objectProxy,這個(gè) objectProxy 具有和 object 一摸一樣的方法,但是這些方法并沒(méi)有 B 進(jìn)程中 object 對(duì)象那些方法的能力,這些方法只需要把把請(qǐng)求參數(shù)交給驅(qū)動(dòng)即可。對(duì)于 A 進(jìn)程來(lái)說(shuō)和直接調(diào)用 object 中的方法是一樣的。
當(dāng) Binder 驅(qū)動(dòng)接收到 A 進(jìn)程的消息后,發(fā)現(xiàn)這是個(gè) objectProxy 就去查詢(xún)自己維護(hù)的表單,一查發(fā)現(xiàn)這是 B 進(jìn)程 object 的代理對(duì)象。于是就會(huì)去通知 B 進(jìn)程調(diào)用 object 的方法,并要求 B 進(jìn)程把返回結(jié)果發(fā)給自己。當(dāng)驅(qū)動(dòng)拿到 B 進(jìn)程的返回結(jié)果后就會(huì)轉(zhuǎn)發(fā)給 A 進(jìn)程,一次通信就完成了 其實(shí)進(jìn)程間通信就是為了實(shí)現(xiàn)數(shù)據(jù)共享。一個(gè)程序不同組件在不同進(jìn)程也叫多進(jìn)程,和倆個(gè)應(yīng)用沒(méi)有本質(zhì)區(qū)別。使用process屬性可以實(shí)現(xiàn)多進(jìn)程,但是會(huì)帶來(lái)很多麻煩,主要原因是共享數(shù)據(jù)會(huì)失敗,弊端有:靜態(tài)和單利失效,同步失效,sharedprefer也變的不可靠等問(wèn)題。
多進(jìn)程通信的方式
1.使用intent的附加信息extras來(lái)傳遞,通過(guò)bundle,傳遞的是bundle支持的類(lèi)型,比如基本數(shù)據(jù)類(lèi)型、實(shí)現(xiàn)pracellable或serializeable的對(duì)象
/**指定包名和帶包名的Activity的名字*/
ComponentName componentName = new ComponentName("com.example.androidaidl", "com.example.androidaidl.MainActivity");
Intent intent = new Intent();
intent.putExtra("id", 1001);
intent.setComponent(componentName);
startActivity(intent);
2.使用文件共享,序列化或是sharedpre,不過(guò)不適用于讀寫(xiě)并發(fā)的操作 3.廣播:Android的廣播是系統(tǒng)級(jí)的,只要傳遞的Action一樣,就可以接收到其他進(jìn)程廣播的消息,廣播中可以通過(guò)Intent傳遞數(shù)據(jù)。 4.scheme協(xié)議是android中的一種頁(yè)面內(nèi)跳轉(zhuǎn)協(xié)議,通過(guò)定義自己的scheme協(xié)議,可以非常方便跳轉(zhuǎn)app中的各個(gè)頁(yè)面,并且傳遞數(shù)據(jù),還是可以通過(guò)H5頁(yè)面跳轉(zhuǎn)指定頁(yè)面等。 5.ContentProvider(進(jìn)程間數(shù)據(jù)共享)和message一樣,底層也是binder,除了oncreate方法其他方法(crud)都是運(yùn)行在bindler線(xiàn)程里。所以在oncerate里不能做耗時(shí)操作。Android本身就提供了不少的ContentProvider訪(fǎng)問(wèn),比如聯(lián)系人、相冊(cè)等。 訪(fǎng)問(wèn)ContentProvider,需要通過(guò)Uri,需要以“content://”開(kāi)頭。在其他應(yīng)用訪(fǎng)問(wèn)通過(guò)uri(主機(jī)名):
ContentResolver resolver = getActivity().getContentResolver();
/**com.mh.getdata/stock這個(gè)要和Provider所在進(jìn)程中添加的Uri一致*/
Uri uri = Uri.parse("content://com.mh.getdata/stock");
Cursor cursor = resolver.query(uri, null, null, null, null);
常規(guī)通訊
只有允許不同應(yīng)用的客戶(hù)端用 IPC 方式訪(fǎng)問(wèn)服務(wù),并且想要在服務(wù)中處理多線(xiàn)程(多任務(wù))時(shí),才有必要使用 AIDL。 如果您不需要執(zhí)行跨越不同應(yīng)用的并發(fā) IPC,就應(yīng)該通過(guò)實(shí)現(xiàn)一個(gè) Binder 創(chuàng)建接口;或者,如果您想執(zhí)行 IPC,但根本不需要處理多線(xiàn)程,則使用 Messenger 類(lèi)來(lái)實(shí)現(xiàn)接口。無(wú)論如何,在實(shí)現(xiàn) AIDL 之前,請(qǐng)您務(wù)必理解綁定服務(wù)。 aidl文檔
1.通過(guò) Messenger進(jìn)行傳遞(handler),在遠(yuǎn)程服務(wù)里創(chuàng)建handler(接收客戶(hù)端發(fā)送的消息)、 Messenger對(duì)像,在onbind里返回( Messenger.getbinder)。在客戶(hù)端綁定服務(wù),拿著 Messenger對(duì)象發(fā)消息(可以用bundle)。在遠(yuǎn)程服務(wù)的handlermessage方法就會(huì)收到。他是一個(gè)個(gè)處理的,如果大量并發(fā)請(qǐng)求用aidl, Messenger底層就是aidl
在客戶(hù)端中創(chuàng)建一個(gè)Messenger。然后,當(dāng)客戶(hù)端收到 onServiceConnected() 回調(diào)時(shí),會(huì)向服務(wù)發(fā)送一條 Message,并在其 send() 方法的 replyTo 參數(shù)中包含客戶(hù)端的 Messenger。 注意:Messenger和Message是倆個(gè)東西
public void sayHello(View v) {
if (!mBound) return;
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
2.直接使用Binder對(duì)象:缺點(diǎn)是這種方式不能進(jìn)行跨進(jìn)程,跨應(yīng)用程序的函數(shù)調(diào)用。只能實(shí)現(xiàn)在同一個(gè)進(jìn)程之中,同一個(gè)應(yīng)用程序之中的不同的組件之間通訊。
用法:繼承Binder,然后在service里return 繼承Binder用它的對(duì)象返回,客戶(hù)端將bind對(duì)象強(qiáng)轉(zhuǎn)成自定義Bind
AIDL
Android interface definition language (android接口定義語(yǔ)言) , 用來(lái)跨進(jìn)程的訪(fǎng)問(wèn)方法。
aidl操作步驟: 1.在兩個(gè)項(xiàng)目中新建普通文件(new ->General->File),后綴名改成(aidl),客戶(hù)端和服務(wù)端中這個(gè)文件所在的包名要保持一致,內(nèi)容也要一樣 編譯之后, 會(huì)在gen目錄下,自動(dòng)產(chǎn)生同名的,后綴為 Java 的文件。里面有我們要用到的 Stub類(lèi)。
public static abstract class Stub extends android.os.Binder implements com.example.aidl.AidlFunctions
2.在接口文件AIDLFunctions.aidl中,我們定義一個(gè)方法 show
interface AidlFunctions{
void show();
}
3.AIDL的使用,需要一個(gè)Service配合,所以我們?cè)诜?wù)端還要聲明一個(gè)Service
public class AIDLService extends Service {
//stub就是系統(tǒng)自動(dòng)產(chǎn)生的
AidlFunctions.Stub binder;
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
binder = new AidlFunctions.Stub() {
@Override
//這里是我們?cè)诮涌谥新暶鞯姆椒ǖ膶?shí)現(xiàn)
public void show() throws RemoteException {
// TODO Auto-generated method stub
System.out.println("--------------------收到----------------------");
}
};
return binder;
}
}
4.客戶(hù)端:
//綁定服務(wù),要用到ServiceConnection
private ServiceConnection serviceConnection;
//自定義的接口,和服務(wù)端一樣
private AidlFunctions aidlFunctions;
serviceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("--------------------ServiceDisconnected----------------------");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("--------------------ServiceConnected----------------------");
aidlFunctions = AidlFunctions.Stub.asInterface(service);
}
};
Intent intent = new Intent("com.example.androidaidl.AIDLService");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
//調(diào)用show方法
try {
aidlFunctions.show();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
使用多進(jìn)程顯而易見(jiàn)的好處就是分擔(dān)主進(jìn)程的內(nèi)存壓力。我們的應(yīng)用越做越大,內(nèi)存越來(lái)越多,將一些獨(dú)立的組件放到不同的進(jìn)程,它就不占用主進(jìn)程的內(nèi)存空間了。當(dāng)然還有其他好處,有些應(yīng)用后臺(tái)是有多個(gè)進(jìn)程的,啟動(dòng)一個(gè)不可見(jiàn)的輕量級(jí)私有進(jìn)程,在后臺(tái)收發(fā)消息,或者做一些耗時(shí)的事情,或者開(kāi)機(jī)啟動(dòng)這個(gè)進(jìn)程,然后做監(jiān)聽(tīng)等。還有就是防止主進(jìn)程被殺守護(hù)進(jìn)程,守護(hù)進(jìn)程和主進(jìn)程之間相互監(jiān)視,有一方被殺就重新啟動(dòng)它。因?yàn)樗鼈円qv后臺(tái),特別是即時(shí)通訊或者社交應(yīng)用。
網(wǎng)站標(biāo)題:Android進(jìn)程通信的方法
轉(zhuǎn)載源于:http://m.fisionsoft.com.cn/article/djsohpc.html


咨詢(xún)
建站咨詢(xún)
