androidipc通信
⑴ android 組件間、進程間數據傳輸和限制
1、Bunder 傳遞對象為什麼需要序列化?
1》因為 bundle 傳遞數據時只支持基本數據類型,所以在傳遞對象時需要序列化轉
換成可存儲或可傳輸的本質狀態(位元組流)。序列化後的對象可以在網路、IPC
(比如啟動另一個進程的 Activity、Service 和 Reciver)之間進行傳輸,也可以 存儲到本地。
2》序列化,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化的原因基本三種 情況:
1.永久性保存對象,保存對象的位元組序列到本地文件中; 2.對象在網路中傳遞;
3.對象在 IPC 間傳遞。
2、序列化Serializable 和Parcelable 的區別
Serializable(java 自帶):
1》Serializable 是序列化的意思,表示將一個對象轉換成存儲或可傳輸的狀態。序列化後的對象可以在網路上進傳輸,也可以存儲到本地。
2》Serializable 會使用反射,序列化和反序列化過程需要大量 I/O 操作。
Parcelable(android 專用):
1》除了 Serializable 之外,使用 Parcelable 也可以實現相同的效果,不過不同於將 對象進行序列化,Parcelable 方式的實現原理是將一個完整的對象進行分解,而分解後的每一部分都是 Intent 所支持的數據類型,這也就實現傳遞對象的功能 了。
2》Parcelable 自已實現封送和解封(marshalled &unmarshalled)操作不需要用反 射,數據也存放在 Native 內存中,效率要快很多。
兩者最大的區別在於 存儲媒介的不同,Serializable 使用 I/O 讀寫存儲在硬碟 上,而 Parcelable 是直接 在內存中讀寫。很明顯,內存的讀寫速度通常大於 IO 讀寫,所以在 Android 中傳遞數據優先選擇 Parcelable。
3、bundle傳輸的數據是否有限制,是多少,為什麼要限制?
1》Intent 在傳遞數據時是有大小限制的,大約限制在 1MB 之內,你用 Intent 傳遞 數據,實際上走的是跨進程通信(IPC),跨進程通信需要把數據從內核 到進程中,每一個進程有一個接收內核數據的緩沖區,默認是 1M;如果一次傳 遞的數據超過限制,就會出現異常。
2》不同廠商表現不一樣有可能是廠商修改了此限制的大小,也可能同樣的對象在不 同的機器上大小不一樣。
3》傳遞大數據,不應該用 Intent;考慮使用 ContentProvider 或者直接匿名共享內 存。簡單情況下可以考慮分段傳輸。
4、匿名共享內存(https://www.jianshu.com/p/d9bc9c668ba6)
⑵ Android的IPC機制
IPC是內部進程通信的簡稱, 是共享」命名管道」的資源。Android中的IPC機制是為了讓Activity和Service之間可以隨時的進行交互,故在Android中該機制,只適用於Activity和Service之間的通信,類似於遠程方法調用,類似於C/S模式的訪問。通過定義AIDL介面文件來定義IPC介面。Servier端實現IPC介面,Client端調用IPC介面本地代理。
⑶ android 進程間的通信(IPC)方式有哪些
Android為了屏蔽進程的概念,利用不同的組件[Activity、Service]來表示進程之間的通信!組件間通信的核心機制是Intent,通過Intent可以開啟一個Activity或Service,不論這個Activity或Service是屬於當前應用還是其它應用的。
一、Intent包含兩部分:
1、目的[action]--要往哪裡去
2、內容[category、data]--路上帶了些什麼,區分性數據或內容性數據
二、Intent類型:
1、顯式--直接指定消息目的地,只適合同一進程內的不同組件之間通信
new Intent(this,Target.class)
2、隱式--AndroidMainifest.xml中注冊,一般用於跨進程通信
new Intent(String action)
IPC機制:有了Intent這種基於消息的進程內或進程間通信模型,我們就可以通過Intent去開啟一個Service,可以通過Intent跳轉到另一個Activity,不論上面的Service或Activity是在當前進程還是其它進程內即不論是當前應用還是其它應用的Service或Activity,通過消息機制都可以進行通信!
⑷ Android跨進程通信
本文整理和引用他人的筆記,旨在個人復習使用。
參考鏈接:
https://blog.csdn.net/fanleiym/article/details/83894399
https://github.com/274942954/AndroidCollection/blob/master/Docs/Android%E7%9F%A5%E8%AF%86%E7%82%B9%E6%B1%87%E6%80%BB.md#%E8%BF%9B%E7%A8%8B%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F
https://www.kaelli.com/4.html
https://carsonho.blog.csdn.net/article/details/73560642?utm_medium=distribute.pc_relevant.none-task-blog--1.e_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog--1.e_weight
默認情況下,一個app只會運行在一個進程中,進程名為app的包名。
1. 分散內存的佔用
Android系統對每個應用進程的內存佔用是有限制的,佔用內存越大的進程,被系統殺死的可能性就越大。使用多進程可以減少主進程佔用的內存,避免OOM問題,降低被系統殺死的概率。
2. 實現多模塊
一個成熟的應用一定是多模塊化的。項目解耦,模塊化,意味著開辟新的進程,有獨立的JVM,帶來數據解耦。模塊之間互不幹預,團隊並行開發,同時責任分工也很明確。
3. 降低程序奔潰率
子進程崩潰不會影響主進程的運行,能降低程序的崩潰率。
4. 實現一些特殊功能
比如可以實現推送進程,使得主進程退出後,能離線完成消息推送服務。還可以實現守護進程,來喚醒主進程達到保活目的。還可以實現監控進程專門負責上報bug,進而提升用戶體驗。
android:process 屬性的值以冒號開頭的就是 私有進程 ,否則就是 公有進程 。當然命名還需要符合規范,不能以數字開頭等等。
1. 前台進程
2. 可見進程
3. 服務進程
4. 後台進程
5. 空進程
Android 會將進程評定為它可能達到的最高級別。另外服務於另一進程的進程其級別永遠不會低於其所服務的進程。
創建新的進程時會創建新的Application對象,而我們通常在Application的onCreate方法中只是完成一些全局的初始化操作,不需要多次執行。
解決思路:獲取當前進程名,判斷是否為主進程,只有主進程的時候才執行初始化操作
獲取當前進程名的兩種方法:
Application中判斷是否是主進程(方法1例子):
Serializable 和 Parcelable是數據序列化的兩種方式,Android中只有進行序列化過後的對象才能通過intent和Binder傳遞。
通常序列化後的對象完成傳輸後,通過反序列化獲得的是一個新對象,而不是原來的對象。
Serializable是java介面,位於java.io的路徑下。Serializable的原理就是把Java對象序列化為二進制文件後進行傳遞。Serializable使用起來非常簡單,只需直接實現該介面就可以了。
Parcelable是Google為了解決Serializable效率低下的問題,為Android特意設計的一個介面。Parcelable的原理是將一個對象完全分解,分解成可以傳輸的數據類型(如基本數據類型)再進行傳遞。
通常需要存到本地磁碟的數據就使用Serializable,其他情況就使用效率更高的Parcelable。
IPC 即 Inter-Process Communication (進程間通信)。Android 基於 Linux,而 Linux 出於安全考慮,不同進程間不能之間操作對方的數據,這叫做「進程隔離」。
每個進程的虛擬內存空間(進程空間)又被分為了 用戶空間和內核空間 , 進程只能訪問自身用戶空間,只有操作系統能訪問內核空間。
由於進程只能訪問自身用戶空間,因此在傳統的IPC中,發送進程需要通過_from_user(系統調用)將數據從自身用戶空間拷貝到內核空間,再由接受進程通過_to_user從內核空間復拷貝到自身用戶空間,共需要拷貝2次,效率十分低下。Android採用的是Binder作為IPC的機制,只需復制一次。
Binder翻譯過來是粘合劑,是進程之間的粘合劑。
Binder IPC通信的底層原理是 通過內存映射(mmap),將接收進程的用戶空間映射到內核空間 ,有了這個映射關系,接收進程就能通過用戶空間的地址獲得內核空間的數據,這樣只需發送進程將數據拷貝到內核空間就可完成通訊。
一次完整的Binder IPC通信:
從IPC的角度看,Binder是一種跨進程通信機制(一種模型),Binder 是基於 C/S 架構的,這個通信機制中主要涉及四個角色:Client、Server、ServiceManager和Binder驅動。
Client、Server、ServiceManager都是運行在用戶空間的進程,他們通過系統調用(open、mmap 和 ioctl)來訪問設備文件/dev/binder,從而實現與Binder驅動的交互。Binder驅動提供進程間通信的能力(負責完成一些底層操作,比如開辟數據接受緩存區等),是Client、Server和ServiceManager之間的橋梁。
Client、Server就是需要進行通信兩個的進程,通信流程:
細心的你一定發現了,注冊服務和獲得服務本身就是和ServiceManager進行跨進程通信。其實和ServiceManager的通信的過程也是獲取Binder對象(早已創建在Binder驅動中,攜帶了注冊和查詢服務等介面方法)來使用,所有需要和ServiceManager通信的進程,只需通過0號引用,就可以獲得這個Binder對象了。
AIDL內部原理就是基於Binder的,可以藉此來分析Binder的使用。
AIDL是介面定義語言,簡短的幾句話就能定義好一個復雜的、內部有一定功能的java介面。
先看看ICallBack.aidl文件,這里定義了一個介面,表示了服務端提供的功能。
被定義出來的java介面繼承了IInterface介面,並且內部提供了一個Stub抽象類給服務端(相當於封裝了一下,服務端只需繼承這個類,然後完成功能的裡面具體的實現)。
參考: https://www.cnblogs.com/sqchen/p/10660939.html
(以下是添加了回調的最終實現,可以看參考鏈接一步一步來)
為需要使用的類,創建aidl文件。
系統會自動在main文件下生成aidl文件夾,並在該文件夾下創建相應目錄。
在java相同路徑下創建Student類,這里不能使用@Parcelize註解,否則會報錯
創建IStudentService.aidl,定義了一個介面,該介面定義了服務端提供的功能。創建完後rebuild一下項目 (每次創建和修改定義介面文件都要rebuild一下)
創建在服務端的StudentService
可以看見有回調,說明客戶端也提供了介面給服務端來回調(雙向通信,此時客戶端的變成了服務端),即ICallBack.aidl
客戶端是通過Binder驅動返回的Binder調用StudentService里的具體實現方法
AIDL使用注意:
Messenger可以在不同進程中傳遞 Message 對象,在Message中放入我們需要傳遞的數據,就可以輕松地實現數據的進程間傳遞了。Messenger 是一種輕量級的 IPC 方案,是對AIDL的封裝,底層實現是 AIDL。
使用詳見: https://blog.csdn.net/qq951127336/article/details/90678698
⑸ Android-IPC
IPC是Inter-Process Communication的縮寫,含義就是跨進程通信。
首先我們要理解什麼是進程,什麼是線程。按敬宏或操作系統的描述,進程是資源分配的最小單位,而線程是CPU調度的最小單位,一個進程可亮伍以包含多個線程(主線程、子線程)。多線程需要考慮並發問題。
Android中的主線程是也叫UI線程,在主線程執行耗時絕跡操作會ANR。
主要包含三部分:Serialiazable,Parcelable以及Binder
Serialiazable與Parcelable的區別:Serialiazable使用簡單但是需要大量I/O操作,Parcelable使用較繁瑣,主要用於內存序列化,效率高。
⑹ 02 項目架構-IPC通信框架
Android App開發中的IPC(進程間通信)無處不在。比如我們使用的 AlarmManager 、 InputMethodService 都是系統為我們提供的服務,處於單獨的進程中。如果需要在自己的App進程中使用這些服務就需要進行IPC通信。
除此之外,我們自己的程序中也會存在進程通信的可能(特別是在一些大型APP中)
QQ:未登陸
微信:使用一段時間後:
場景:在Service中開啟定位服務,Service處於單獨的進程,需要在App主進程或者其他APP中獲得定位結果。
服務中提供暴露給其他進程使用的方法並提供一個 ServiceId 註解標記,而服務實現中必須給到相同的 ServiceId 與方法實現,不強制要求 LocationManager 一定需要繼承 ILocationManager j介面,但是為了保證方法簽名統一建議繼承。(不然一個是getLocation,另一個是getLocation2就不好玩了)
在Service進行定位,定位結果在 LocationManager 中記錄。在這個Service中使用框架注冊 LocationManager 。
不需要返回 Binder 對象,這意味著使用者不需要編寫繁瑣沒任何提示的AIDL文件。
框架內部會提供 com.enjoy.ipc.IPCService$IPCServiceX 多個預留Service,用於與其他進程通信,如果一個App存在多個進程都需要提供各自進程的服務,可以使用不同的Service。所以本質上依然是藉助的Service+Binder通信,但框架將細節封裝隱藏,使用更加簡單。
獲得結果對象後就能像調用本地方法一樣調用遠程方法(RPC調用)。
在使用中簡化了:
1、不需要自己定義AIDL介面,使用的JavaBean也不要求實現 Parcelable 介面;
2、在客戶端不需要直接使用 bindService 獲得 Binder 對象;
服務端需要定義暴露服務的介面(ILocationManager),客戶端如果是其他APP,則需要將介面類放到自己的源碼中(不需要介面實現)。介面中定義的方法就是服務端提供給其他進程使用的方法。
整個框架包含了服務端與客戶端兩端介面。
在服務進程中會緩存 ServiceId 與對應的服務實現Class對象: 服務表 ,同時服務實現中的所有方法列表也需要進行記錄: 方法表 。由於一個服務中可能存在多個方法,所以其數據結構為 Map<Class,Map<String,Method>> ,外層 Map 的key為服務Class,內層 Map 的key則為方法標記。
當客戶端需要調用服務時,將 ServiceId 、MethodName以及執行方法需要的參數傳遞給服務端,服務端查表利用反射 Method#invoke 即可執行服務中的方法。
其中客戶端的請求被封裝為 Request 對象,服務端響應則封裝為 Response 對象
服務端只需要暴露服務介面給其他進程使用,所以服務端只需要調用框架的注冊介面 regiest 對服務實現進行注冊。( 注冊的是服務實現,而不是服務介面 )
注冊時,通過反射獲得Class上的 ServiceId 即可記錄 服務表 。同時利用反射獲得Class中所有的public Method即可記錄 方法表 。
由於框架本質還是利用Binder來完成通信,為了與其他進程通信,框架內部提供了多個預留的Service。
通信Service會返回一個AIDL生成的Binder類對象
客戶端使用 send 方法向服務端發起請求。
服務端接收到請求後的實現:
客戶端需要先與服務端建立連接,因此框架中提供了 connect 方法,內部封裝 bindService 實現與服務端通信Service( IPCService )的綁定。
唯一需要注意的是:
當完成綁定後,客戶端就可以獲得服務端通信Service提供的 IIPCService 對象,客戶端調用 IIPCService#send 發起請求。
當我們需要獲得 Location 。則應該調用 LocationManager.getDefault().getLocation() 。這句調用會需要執行 LocationManager 的兩個方法: getDefault 與 getLocation 。
然而這個對象存在服務端,客戶端如何獲得?
我們可以利用動態代理,在客戶端創建一個 "假的" 服務介面對象(代理)。
當我們執行這個代理對象的方法( getLocation )時,會回調 IPCInvocationHandler#invoke 方法,在這個方法中框架會向服務端發起請求: IIPCService#send
而 getLocation 會返回一個 Location 記錄定位信息的對象,這個對象會被服務端json序列化發送過來,因此,客戶端只需要在此處獲得 Method 的返回類型並反序列化即可。
RPC指的是:從客戶端上通過參數傳遞的方式調用伺服器上的一個函數並得到返回的結果,隱藏底層的通訊細節。在使用形式上像調用本地函數一樣去調用遠程的函數。
比如我們使用Okhttp進行網路請求:
這種方式很顯然不是RPC。
而使用Retrofit:
RPC:我們調用遠程的XXX方法,就像在調用本地方法一樣。
⑺ Android IPC機制
IPC是指兩個進程之間進行數據交互的過程,即:跨進程通信。
進程是一個執行單,在移動設備上指一個程序或者一個應用。一個進程可以有多個線程,也可以只有一個線程,即主線程。在Android里邊,主線程也叫作UI線程,要是在主線程執行大量耗時任務,就會造成界面無法響應,ANR問題,解決這類問題,把耗時操作放在子線程就好。
在Android中,最有特色的進程間通信就是Binder,Binder輕松的實現了進程間的通信。
給四大組件 Activity、Service、Receiver、ContentProvider 在AndroidMenifeist中指定 android:process 屬性,可以指定其運行的進程。
: 開頭的線程是當前應用的私有進程,其它應用不可以和它跑在同一個進程中,而不以 : 開頭的屬於全局進程,其他應用通過ShareUID方式可以和它跑在一個進程中。
Android為了每一個應用(進程)都分配了獨立的虛擬機,不同的虛擬機在內存分配上有不同的地址空間。
多進程會造成如下幾個反面方面的問題:
為了解決這些問題,系統提供了跨進程通信方法,雖然不能直接共享內存,但是可以實現數據共享。Intent來傳遞數據,共享文件,基於Binder的Messenger,ContentProvider,AIDL和Socket。
當我們需要通過Intent和Binder傳輸數據,或者我們需要把對象持久化到存儲設備上,再或者通過網路傳輸給其它客戶端時,Serializable和Parcelable介面可以完成對象的序列化過程。
Serialzable是java提供的序列化介面,是一個空介面,為對象同序列化和反序列化操作。
想讓一個類對象實現序列化,只需要這個類實現Serialzable介面,並聲明一個serialVersionUID即可,serialVersionUID可以聲明成1L或者IDE根據當前類介面自動生成它的hash值。
沒有serialVersionUID不影響序列化,但是可能會影響反序列化。序列化時,系統當前類的serialVersionUID寫入序列化文件中,當反序列化時,回去檢測文件中的serialVersionUID,看它是否和當前類的serialVersionUID一致,如果不一致,無法完成反序列化。
Seriallizable用起來簡單但是開銷大,序列化和反序列過程需要大量的I/O操作,而Parcelable是Android序列化方式,更適合Android平台,效率更高。Parcelable主要用於內存序列化上,而Seriallizable更適用於序列化到本地存儲設備,或者將對象序列化後通過網路傳輸到別的客戶端。
Activity、Service、Receiver都支持在 Intent中傳遞Bundle數據,Bundle實現了Pareclable介面,所以它可以方便地在不同進程間傳輸。
Android基於Linux,使得其並發讀寫文件可以沒有限制的進行,兩個進程可以通過讀寫一個文件來交換數據。共享數據對文件格式沒有要求,雙反約定就行。使用文件共享很有可能出問題。
SharedPreferences是個特例,雖然也是屬於文件的一種,但是由於系統對它的讀寫有一定的緩存策略,即在內存中會有一份SharedPreferences文件的緩存,因此在多進程模式下,系統對他的讀寫變得不可靠,高並發的時候,很大可能會丟失數據。
Messenger可以在不同的進程中傳遞Message對象,在Message中存入我們需要傳遞的數據,就可以實現數據的跨進程傳遞。它是一種輕量級的IPC方案,底層實現是AIDL。
Messenger對AIDL做了封裝,使得我們可以更便捷的實現跨進程通信,它一次只處理一個請求,在服務端不用考慮線程同步問題,在服務端不存在並發執行的情形。實現一個Messenger有如下幾個步驟:
在服務端創建一個Service,同時創建一個Handler,並通過它來創建一個Messenger對象,然後再Service的onBind中返回這個Messenger對象底層Binder即可。
綁定服務端Service,綁定成功後用服務端返回的IBinder對象創建一個Messenger。通過這個對象就可以向服務端發消息了。如果需要服務端回應客戶端,就需要和服務端一樣,創建一個Handler,並通過它來創建一個Messenger對象,然後把這個Messenger對象通過Message的replyTo參數傳給服務端,服務端可以通過這個replyTo參數回應客戶端。
首先要創建一個Service用來監聽客戶端的連接請求,然後創建一個AIDL文件,將暴露給客戶端的介面在這個AIDL文件中聲明,最後在Service中實現AIDL介面即可。
綁定服務端的Service,將服務端返回的Binder對象轉成AIDL介面所屬的類型,接著就可可以範文AIDL里邊的方法了。
在AIDL文件中,並不是所有的額數據類型都是可以使用的。
以上6種數據就是AIDL所支持的所有類型,其中自定義的Parecelable對象和AIDL對象必須顯示的import,不管是否和當前的AIDL文件位於同一個包。
AIDL文件中用到了自定義的Parcelable對象,必須新建一個同名的AIDL文件,在其中聲明它為parcelable類型。
AIDL中除了基礎數據類型,其它類型參數都需要標上方向:in、out、inout,in是輸入型參數,out是輸出型參數,inout是輸入輸出型參數。
上面是遠程服務端示例,AIDL方法在服務端的Binder線程池中執行,因此各個客戶端同時連接的時候,會存在多個線程同時訪問的情形,所以要在AIDL中處理線程同步,這個CopyOnWriteArrayList支持並發的讀寫。
AIDL所支持的是一個抽象的List,只是一個介面,因此雖然服務端返回的是CopyOnWriteArrayList,當時Binder會按照List規范去範文數據並最終形成一個ArrayList傳遞給客戶端。
ServiceConnection 的回調方法在UI線程中運行,服務端的方法有可能很久才能執行完畢,需要考慮ANR的問題。
服務的方法本省就運行再Binder線程池中,本身可以執行大量耗時操作,不要去服務端方法中開縣城去進行非同步任務。
客戶端
服務端
RemoteCallbackList是系統提供專門用於刪除跨進程listener的,它的內部有一個Map結構,用來保存所有的AIDL回調,這個Map的key就是Binder類型,value是CallBack類型。
客戶端解注冊的時候,我們只需要遍歷服務端所有的listener,找出那個和接注冊listener具有相同的Binder對象的服務端listener並把它刪除即可。
RemoteCallbackList的beginBroadcast和finishBroadcast必須配對使用。
ContentProvider是Android專門提供不同應用間進行數據共享的方式。底層實現一樣是Binder。
系統預置了許多ContentProvider,比如通訊錄,日程信息表,只需要通過ContentResolver的query、update、insert、delete方法即可。
⑻ 安卓IPC跨進程通訊:AIDL+Retrofit——AndLinker的初步使用
需要用到安卓跨進程通訊,明指IPC (進程間通信) 的時候,AndLinker是一款Android上的IPC (進程間通信) 庫,結合了 AIDL 和 Retrofit 的諸多特性,且可以與 RxJava 和 RxJava2 的Call Adapters無縫結合使用。
個人簡單理解就是:簡化AIDL流程的一個第三方庫。使用時斗昌需要先了解一下AIDL、retrofit。
以普通Java介面代替AIDL介面
像 Retrofit 一樣生成遠程服務介面的IPC實現
支持的Call Adapters:Call, RxJava Observable, RxJava2 Observable & Flowable
支持遠程服務回調機制
支持AIDL的所有數據類型
支持AIDL的所有數據定向tag:in,out,inout
支持AIDL的oneway關鍵字
在服務端以及客戶端的項目根目錄的build.gradle中添加jcenter()倉庫
在App的build.gradle中添加如下依賴
AndLinker支持AIDL所有數據類型:
Java語言中的所有原始類型 (如:int,long,char,boolean,等等)
String
CharSequence
Parcelable
List (List中的所有元素必須是此列表中支持的數據類型)
Map (Map中的所有元素必須是此列表中支持的數據類型)
介面里的方法就是按需激銷配求需創建。這里只舉幾個簡單的示例。