摘要:實(shí)際開(kāi)發(fā)中案例操作通信業(yè)務(wù)需求多進(jìn)程通信應(yīng)用服務(wù)端某客戶(hù)端調(diào)試工具。當(dāng)服務(wù)端和客戶(hù)端位于同一個(gè)進(jìn)程時(shí),方法調(diào)用不會(huì)走跨進(jìn)程的過(guò)程,當(dāng)兩者處于不同晉城市,方法調(diào)用走過(guò)程,這個(gè)邏輯由的內(nèi)部代理類(lèi)完成。
目錄介紹
1.問(wèn)題答疑
2.Aidl相關(guān)屬性介紹
2.1 AIDL所支持的數(shù)據(jù)類(lèi)型
2.2 服務(wù)端和客戶(hù)端
2.3 AIDL的基本概念
3.實(shí)際開(kāi)發(fā)中案例操作
3.1 aidl通信業(yè)務(wù)需求
3.2 操作步驟偽代碼
3.3 服務(wù)端操作步驟
3.4 客戶(hù)端操作步驟
3.5 測(cè)試
4.可能出現(xiàn)的問(wèn)題
4.1 客戶(hù)端在子線程中發(fā)起通信訪問(wèn)問(wèn)題
4.2 什么情況下會(huì)導(dǎo)致遠(yuǎn)程調(diào)用失敗
4.3 設(shè)置aidl的權(quán)限,需要通過(guò)權(quán)限才能調(diào)用
5.部分源碼解析
5.1 服務(wù)端aidl編譯生成的java文件
5.2 客戶(hù)端綁定服務(wù)端service原理
關(guān)于aidl應(yīng)用案例https://github.com/yangchong2...
關(guān)于所有的博客筆記均已開(kāi)源,是markdown格式,鏈接地址:https://github.com/yangchong2...
1.問(wèn)題答疑1.1.0 AIDL所支持的數(shù)據(jù)類(lèi)型有哪些?
1.1.1 提供給客戶(hù)端連接的service什么時(shí)候運(yùn)行?
1.1.2 Stub類(lèi)是干什么用的呢?
1.1.3 如何解決遠(yuǎn)程調(diào)用失敗的問(wèn)題?
2.Aidl相關(guān)屬性介紹 2.1 AIDL所支持的數(shù)據(jù)類(lèi)型
在AIDL中,并非支持所有數(shù)據(jù)類(lèi)型,他支持的數(shù)據(jù)類(lèi)型如下所示:
基本數(shù)據(jù)類(lèi)型(int、long、char、boolean、double、float、byte、short)
String和CharSequence
List:只支持ArrayList,并且里面的每個(gè)元素必須被AIDL支持
Map: 只支持HashMap, 同樣的,里面的元素都必須被AIDL支持,包括key和value
Parcelable:所有實(shí)現(xiàn)了Parcelable接口的對(duì)象
AIDL: 所有的AIDL接口本身也可以在AIDL 文件中使用
2.2 服務(wù)端和客戶(hù)端
2.2.1 服務(wù)端
注意:服務(wù)端就是你要連接的進(jìn)程。服務(wù)端給客戶(hù)端一個(gè)Service,在這個(gè)Service中監(jiān)聽(tīng)客戶(hù)端的連接請(qǐng)求,然后創(chuàng)建一個(gè)AIDL接口文件,里面是將要實(shí)現(xiàn)的方法,注意這個(gè)方法是暴露給客戶(hù)端的的。在Service中實(shí)現(xiàn)這個(gè)AIDL接口即可
2.2.2 客戶(hù)端
客戶(hù)端首先需要綁定服務(wù)端的Service,綁定成功后,將服務(wù)端返回的Binder對(duì)象轉(zhuǎn)換成AIDL接口所屬的類(lèi)型,最后調(diào)用AIDL的方法就可以了。
2.3 AIDL的基本概念AIDL:Android Interface Definition Language,即Android接口定義語(yǔ)言;用于讓某個(gè)Service與多個(gè)應(yīng)用程序組件之間進(jìn)行跨進(jìn)程通信,從而可以實(shí)現(xiàn)多個(gè)應(yīng)用程序共享同一個(gè)Service的功能。
3.實(shí)際開(kāi)發(fā)中案例操作 3.1 aidl通信業(yè)務(wù)需求aidl多進(jìn)程通信應(yīng)用——服務(wù)端:某app;客戶(hù)端:app調(diào)試工具。注意:aidl多進(jìn)程通信是指兩個(gè)獨(dú)立app之間的通信……
打開(kāi)app調(diào)試工具,可以通過(guò)綁定服務(wù)端某app的service,獲取到公司app的信息,比如渠道,版本號(hào),簽名,打包時(shí)間,token等屬性
通過(guò)app調(diào)試工具,可以通過(guò)aidl接口中的方法設(shè)置屬性,設(shè)置成功后,查看某app是否設(shè)置屬性成功
3.2 操作步驟偽代碼
3.2.1 服務(wù)端
步驟1:新建定義AIDL文件,并聲明該服務(wù)需要向客戶(hù)端提供的接口
補(bǔ)充,如果aidl中有對(duì)象,則需要?jiǎng)?chuàng)建對(duì)象,并且實(shí)現(xiàn)Parcelable
步驟2:在Service子類(lèi)中實(shí)現(xiàn)AIDL中定義的接口方法,并定義生命周期的方法(onCreat、onBind()、blabla)
步驟3:在AndroidMainfest.xml中注冊(cè)服務(wù) & 聲明為遠(yuǎn)程服務(wù)
3.2.2 客戶(hù)端
步驟1:拷貝服務(wù)端的AIDL文件到目錄下
步驟2:使用Stub.asInterface接口獲取服務(wù)器的Binder,根據(jù)需要調(diào)用服務(wù)提供的接口方法
步驟3:通過(guò)Intent指定服務(wù)端的服務(wù)名稱(chēng)和所在包,綁定遠(yuǎn)程Service
3.3 服務(wù)端操作步驟
3.3.1 創(chuàng)建一個(gè)aidl文件【注意:在main路徑下創(chuàng)建】
可以看到里面有一個(gè)AppInfo,注意這個(gè)類(lèi)需要自己創(chuàng)建,并且手動(dòng)導(dǎo)包進(jìn)來(lái)。否則編譯時(shí)找不到……
// ICheckAppInfoManager.aidl package cn.ycbjie.ycaudioplayer; import cn.ycbjie.ycaudioplayer.AppInfo; // Declare any non-default types here with import statements interface ICheckAppInfoManager { //獲取app信息,比如token,版本號(hào),簽名,渠道等信息 ListgetAppInfo(String sign); boolean setToken(String sign,String token); boolean setChannel(String sign,String channel); boolean setAppAuthorName(String sign,String name); }
3.3.2 創(chuàng)建一個(gè)AppInfo類(lèi),實(shí)現(xiàn)Parcelable接口
這個(gè)類(lèi)就是需要用的實(shí)體類(lèi),因?yàn)槭强邕M(jìn)程,所以實(shí)現(xiàn)了Parcelable接口,這個(gè)是Android官方提供的,它里面主要是靠Parcel來(lái)傳遞數(shù)據(jù),Parcel內(nèi)部包裝了可序列化的數(shù)據(jù),能夠在Binder中自由傳輸數(shù)據(jù)。
注意:如果用到了自定義Parcelable對(duì)象,就需要?jiǎng)?chuàng)建一個(gè)同名的AIDL文件,包名要和實(shí)體類(lèi)包名一致。我之前這個(gè)地方?jīng)]加,導(dǎo)致出現(xiàn)錯(cuò)誤!
如圖所示:
import android.os.Parcel; import android.os.Parcelable; public class AppInfo implements Parcelable { private String key; private String value; public AppInfo(String key, String value) { this.key = key; this.value = value; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.key); dest.writeString(this.value); } public AppInfo() { } protected AppInfo(Parcel in) { this.key = in.readString(); this.value = in.readString(); } public static final CreatorCREATOR = new Creator () { @Override public AppInfo createFromParcel(Parcel source) { return new AppInfo(source); } @Override public AppInfo[] newArray(int size) { return new AppInfo[size]; } }; @Override public String toString() { return "AppInfo{" + "key="" + key + """ + ", value="" + value + """ + "}"; } }
3.3.3 在Service子類(lèi)中實(shí)現(xiàn)AIDL中定義的接口方法,并定義生命周期的方法(onCreat、onBind()等)
重寫(xiě)的onBinde()方法中返回Binder對(duì)象,這個(gè)Binder對(duì)象指向IAdvertManager.Stub(),這個(gè)Stub類(lèi)并非我們自己創(chuàng)建的,而是AIDL自動(dòng)生成的。系統(tǒng)會(huì)為每個(gè)AIDL接口在build/source/aidl下生成一個(gè)文件夾,它的名稱(chēng)跟你命名的AIDL文件夾一樣,里面的類(lèi)也一樣。
創(chuàng)建binder對(duì)象,在這個(gè)getAppInfo方法中,可以設(shè)置app基本信息,方便后期多進(jìn)程通信測(cè)試
/** ** @author yangchong * blog : * time : 2018/05/30 * desc : 用于aidl多進(jìn)程通信服務(wù)service * revise: **/ public class AppInfoService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { LogUtils.i("AppInfoService--IBinder:"); return binder; } @Override public void onCreate() { super.onCreate(); LogUtils.i("AppInfoService--onCreate:"); } @Override public void onDestroy() { super.onDestroy(); LogUtils.i("AppInfoService--onDestroy:"); } /** * 1.核心,Stub里面的方法運(yùn)行的binder池中。 * 2.Stub類(lèi)并非我們自己創(chuàng)建的,而是AIDL自動(dòng)生成的。 * 系統(tǒng)會(huì)為每個(gè)AIDL接口在build/generated/source/aidl下生成一個(gè)文件夾,它的名稱(chēng)跟你命名的AIDL文件夾一樣 * 3.Stub類(lèi),是一個(gè)內(nèi)部類(lèi),他本質(zhì)上是一個(gè)Binder類(lèi)。當(dāng)服務(wù)端和客戶(hù)端位于同一個(gè)進(jìn)程時(shí),方法調(diào)用不會(huì)走跨進(jìn)程的transact過(guò)程, * 當(dāng)兩者處于不同晉城市,方法調(diào)用走transact過(guò)程,這個(gè)邏輯由Stub的內(nèi)部代理類(lèi)Proxy完成。 */ private final IBinder binder = new ICheckAppInfoManager.Stub() { @Override public ListgetAppInfo(String sign) throws RemoteException { List list=new ArrayList<>(); String aidlCheckAppInfoSign = AppToolUtils.getAidlCheckAppInfoSign(); LogUtils.e("AppInfoService--AppInfoService",aidlCheckAppInfoSign+"-------------"+sign); if(!aidlCheckAppInfoSign.equals(sign)){ return list; } list.add(new AppInfo("app版本號(hào)(versionName)", BuildConfig.VERSION_NAME)); list.add(new AppInfo("app版本名稱(chēng)(versionCode)", BuildConfig.VERSION_CODE+"")); list.add(new AppInfo("打包時(shí)間", BuildConfig.BUILD_TIME)); list.add(new AppInfo("app包名", getPackageName())); list.add(new AppInfo("app作者", SPUtils.getInstance(Constant.SP_NAME).getString("name","楊充"))); list.add(new AppInfo("app渠道", SPUtils.getInstance(Constant.SP_NAME).getString("channel"))); list.add(new AppInfo("token", SPUtils.getInstance(Constant.SP_NAME).getString("token"))); list.add(new AppInfo("App簽名", AppToolUtils.getSingInfo(getApplicationContext(), getPackageName(), AppToolUtils.SHA1))); return list; } @Override public boolean setToken(String sign, String token) throws RemoteException { if(!AppToolUtils.getAidlCheckAppInfoSign().equals(sign)){ return false; } SPUtils.getInstance(Constant.SP_NAME).put("token",token); LogUtils.i("AppInfoService--setToken:"+ token); return true; } @Override public boolean setChannel(String sign, String channel) throws RemoteException { if(!AppToolUtils.getAidlCheckAppInfoSign().equals(sign)){ return false; } SPUtils.getInstance(Constant.SP_NAME).put("channel",channel); LogUtils.i("AppInfoService--setChannel:"+ channel); return true; } @Override public boolean setAppAuthorName(String sign, String name) throws RemoteException { if(!AppToolUtils.getAidlCheckAppInfoSign().equals(sign)){ return false; } SPUtils.getInstance(Constant.SP_NAME).put("name",name); LogUtils.i("AppInfoService--setAppAuthorName:"+ name); return true; } }; }
3.3.4 在AndroidMainfest.xml中注冊(cè)服務(wù) & 聲明為遠(yuǎn)程服務(wù)
在清單文件注冊(cè)即可,需要設(shè)置action。這個(gè)在客戶(hù)端中綁定服務(wù)service需要用到!
3.4 客戶(hù)端操作步驟
3.4.1 拷貝服務(wù)端的AIDL文件到目錄下
注意:復(fù)制時(shí)不要改動(dòng)任何東西!
如圖所示:
3.4.2 通過(guò)Intent指定服務(wù)端的服務(wù)名稱(chēng)和所在包,綁定遠(yuǎn)程Service
通過(guò)Intent指定服務(wù)端的服務(wù)名稱(chēng)和所在包,進(jìn)行Service綁定;
創(chuàng)建ServiceConnection對(duì)象
/** * 跨進(jìn)程綁定服務(wù) */ private void attemptToBindService() { Intent intent = new Intent(); //通過(guò)Intent指定服務(wù)端的服務(wù)名稱(chēng)和所在包,與遠(yuǎn)程Service進(jìn)行綁定 //參數(shù)與服務(wù)器端的action要一致,即"服務(wù)器包名.aidl接口文件名" intent.setAction("cn.ycbjie.ycaudioplayer.service.aidl.AppInfoService"); //Android5.0后無(wú)法只通過(guò)隱式Intent綁定遠(yuǎn)程Service //需要通過(guò)setPackage()方法指定包名 intent.setPackage(packName); //綁定服務(wù),傳入intent和ServiceConnection對(duì)象 bindService(intent, connection, Context.BIND_AUTO_CREATE); } /** * 創(chuàng)建ServiceConnection的匿名類(lèi) */ private ServiceConnection connection = new ServiceConnection() { //重寫(xiě)onServiceConnected()方法和onServiceDisconnected()方法 // 在Activity與Service建立關(guān)聯(lián)和解除關(guān)聯(lián)的時(shí)候調(diào)用 @Override public void onServiceDisconnected(ComponentName name) { Log.e(getLocalClassName(), "無(wú)法綁定aidlServer的AIDLService服務(wù)"); mBound = false; } //在Activity與Service建立關(guān)聯(lián)時(shí)調(diào)用 @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(getLocalClassName(), "完成綁定aidlServer的AIDLService服務(wù)"); //使用IAppInfoManager.Stub.asInterface()方法獲取服務(wù)器端返回的IBinder對(duì)象 //將IBinder對(duì)象傳換成了mAIDL_Service接口對(duì)象 messageCenter = ICheckAppInfoManager.Stub.asInterface(service); mBound = true; if (messageCenter != null) { try { //鏈接成功 Toast.makeText(MainActivity.this,"鏈接成功",Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); } } } };
3.4.3 使用Stub.asInterface接口獲取服務(wù)器的Binder,根據(jù)需要調(diào)用服務(wù)提供的接口方法
通過(guò)步驟3.4.2完成了跨進(jìn)程綁定服務(wù),接下來(lái)通過(guò)調(diào)用方法獲取到數(shù)據(jù)。這里可以調(diào)用getAppInfo方法獲取到服務(wù)端[app]的數(shù)據(jù)
private void getAppInfo() { //如果與服務(wù)端的連接處于未連接狀態(tài),則嘗試連接 if (!mBound) { attemptToBindService(); Toast.makeText(this, "當(dāng)前與服務(wù)端處于未連接狀態(tài),正在嘗試重連,請(qǐng)稍后再試", Toast.LENGTH_SHORT).show(); return; } if (messageCenter == null) { return; } try { List3.5 測(cè)試info = messageCenter.getAppInfo(Utils.getSign(packName)); if(info==null || (info.size()==0)){ Toast.makeText(this, "無(wú)法獲取數(shù)據(jù),可能是簽名錯(cuò)誤!", Toast.LENGTH_SHORT).show(); }else { mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); FirstAdapter adapter = new FirstAdapter(info, this); mRecyclerView.setAdapter(adapter); adapter.setOnItemClickListener(new FirstAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { } }); } } catch (RemoteException e) { e.printStackTrace(); } }
最后看看通過(guò)測(cè)試工具[客戶(hù)端]跨進(jìn)程獲取服務(wù)端app信息截圖
具體可以通過(guò)實(shí)際案例操作:后來(lái)發(fā)現(xiàn)跨進(jìn)程通信原來(lái)挺好玩的……項(xiàng)目地址:https://github.com/yangchong2...
如圖所示:
4.可能出現(xiàn)的問(wèn)題 4.1 客戶(hù)端在子線程中發(fā)起通信訪問(wèn)問(wèn)題當(dāng)客戶(hù)端發(fā)起遠(yuǎn)程請(qǐng)求時(shí),客戶(hù)端會(huì)掛起,一直等到服務(wù)端處理完并返回?cái)?shù)據(jù),所以遠(yuǎn)程通信是很耗時(shí)的,所以不能在子線程發(fā)起訪問(wèn)。由于服務(wù)端的Binder方法運(yùn)行在Binder線程池中,所以應(yīng)采取同步的方式去實(shí)現(xiàn),因?yàn)樗呀?jīng)運(yùn)行在一個(gè)線程中呢。
4.2 什么情況下會(huì)導(dǎo)致遠(yuǎn)程調(diào)用失敗Binder是會(huì)意外死亡的。如果服務(wù)端的進(jìn)程由于某種原因異常終止,會(huì)導(dǎo)致遠(yuǎn)程調(diào)用失敗,如果我們不知道Binder連接已經(jīng)斷裂, 那么客戶(hù)端就會(huì)受到影響。不用擔(dān)心,Android貼心的為我們提供了連個(gè)配對(duì)的方法linkToDeath和unlinkToDeath,通過(guò)linkToDeath我們可以給Binder設(shè)置一個(gè)死亡代理,當(dāng)Binder死亡時(shí),我們就會(huì)收到通知。
// 在創(chuàng)建ServiceConnection的匿名類(lèi)中的onServiceConnected方法中 // 設(shè)置死亡代理 messageCenter.asBinder().linkToDeath(deathRecipient, 0); /** * 給binder設(shè)置死亡代理 */ private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if(messageCenter == null){ return; } messageCenter.asBinder().unlinkToDeath(deathRecipient, 0); messageCenter = null; //這里重新綁定服務(wù) attemptToBindService(); } };4.3 設(shè)置aidl的權(quán)限,需要通過(guò)權(quán)限才能調(diào)用
5.部分源碼解析 5.1 服務(wù)端aidl編譯生成的java文件//在AppInfoService服務(wù)中驗(yàn)證權(quán)限 @Nullable @Override public IBinder onBind(Intent intent) { LogUtils.i("AppInfoService--IBinder:"); int check = checkCallingOrSelfPermission("aidl.AppInfoService"); if(check == PackageManager.PERMISSION_DENIED){ return null; } return binder; }
5.1.1 首先找到aidl編譯生成的Java文件
5.1.2 分析生成的java文件
這個(gè)ICheckAppInfoManager.java就是系統(tǒng)為我們生成的相應(yīng)java文件,簡(jiǎn)單說(shuō)下這個(gè)類(lèi)。它聲明了三個(gè)方法getAppInfo,setToken和setChannel,分明就是我們AIDL接口中的三個(gè)方法。同時(shí)他聲明了3個(gè)id用來(lái)標(biāo)識(shí)這幾個(gè)方法,id用于標(biāo)識(shí)在transact過(guò)程中客戶(hù)端請(qǐng)求的到底是哪個(gè)方法。接著就是我們的Stub,可以看到它是一個(gè)內(nèi)部類(lèi),他本質(zhì)上是一個(gè)Binder類(lèi)。當(dāng)服務(wù)端和客戶(hù)端位于同一個(gè)進(jìn)程時(shí),方法調(diào)用不會(huì)走跨進(jìn)程的transact過(guò)程,當(dāng)兩者處于不同晉城市,方法調(diào)用走transact過(guò)程,這個(gè)邏輯由Stub的內(nèi)部代理類(lèi)Proxy完成。
這個(gè)Stub對(duì)象之所以里面有我們AIDL的接口,正是因?yàn)楣俜教嫖覀冏龊昧耍覀冎灰谶@里具體實(shí)現(xiàn)就好了。
5.2 客戶(hù)端綁定服務(wù)端service原理客戶(hù)端也非常簡(jiǎn)單,首先我們連接到服務(wù)端Service,在連接成功時(shí),也就是onServiceConnected方法里,通過(guò)asInterface(service)方法可以將服務(wù)端的Binder對(duì)象轉(zhuǎn)換成客戶(hù)端所需的AIDL的接口的對(duì)象。這種轉(zhuǎn)換是區(qū)分進(jìn)程的,如果是同一進(jìn)程,那么此方法返回的就是Stub本身,否則返回的就是系統(tǒng)Stub.proxy對(duì)象。拿到接口對(duì)象之后,我們就能夠調(diào)用相應(yīng)方法進(jìn)行自己的處理
參考文章Android 進(jìn)階7:進(jìn)程通信之 AIDL 的使用:https://blog.csdn.net/u011240...
Android中AIDL的使用詳解:https://www.jianshu.com/p/d1f...
Android Aidl的使用:https://blog.csdn.net/menglon...
安卓中AIDL的使用:https://blog.csdn.net/qq_3200...
關(guān)于其他內(nèi)容介紹 01.關(guān)于博客匯總鏈接1.技術(shù)博客匯總
2.開(kāi)源項(xiàng)目匯總
3.生活博客匯總
4.喜馬拉雅音頻匯總
5.其他匯總
02.關(guān)于我的博客我的個(gè)人站點(diǎn):www.yczbj.org,www.ycbjie.cn
github:https://github.com/yangchong211
知乎:https://www.zhihu.com/people/...
簡(jiǎn)書(shū):http://www.jianshu.com/u/b7b2...
csdn:http://my.csdn.net/m0_37700275
喜馬拉雅聽(tīng)書(shū):http://www.ximalaya.com/zhubo...
開(kāi)源中國(guó):https://my.oschina.net/zbj161...
泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...
郵箱:yangchong211@163.com
阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV
segmentfault頭條:https://segmentfault.com/u/xi...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77281.html
摘要:前言進(jìn)程間通信簡(jiǎn)稱(chēng)就是指進(jìn)程與進(jìn)程之間進(jìn)行通信一般來(lái)說(shuō)一個(gè)只有一個(gè)進(jìn)程但是可能會(huì)有多個(gè)線程所以我們用得比較多的是多線程通信比如但是在一些特殊的情況下我們會(huì)需要多個(gè)進(jìn)程或者是我們?cè)谶h(yuǎn)程服務(wù)調(diào)用時(shí)就需要跨進(jìn)程通信了設(shè)置多進(jìn)程設(shè)置多進(jìn)程的步驟很 前言: 進(jìn)程間通信(Inter-Process Communication),簡(jiǎn)稱(chēng)IPC,就是指進(jìn)程與進(jìn)程之間進(jìn)行通信.一般來(lái)說(shuō),一個(gè)app只有一個(gè)...
摘要:中為何新增來(lái)作為主要的方式運(yùn)行機(jī)制是怎樣的機(jī)制有什么優(yōu)勢(shì)運(yùn)行機(jī)制是怎樣的基于通信模式,除了端和端,還有兩角色一起合作完成進(jìn)程間通信功能。 目錄介紹 2.0.0.1 什么是Binder?為什么要使用Binder?Binder中是如何進(jìn)行線程管理的?總結(jié)binder講的是什么? 2.0.0.2 Android中進(jìn)程和線程的關(guān)系?什么是IPC?為何需要進(jìn)行IPC?多進(jìn)程通信可能會(huì)出現(xiàn)什么問(wèn)...
閱讀 2034·2021-11-11 16:54
閱讀 2111·2019-08-30 15:55
閱讀 3611·2019-08-30 15:54
閱讀 391·2019-08-30 15:44
閱讀 2228·2019-08-30 10:58
閱讀 424·2019-08-26 10:30
閱讀 3048·2019-08-23 14:46
閱讀 3191·2019-08-23 13:46