㈠ android進程間通信
1. 簡要說說進程與線程的區別和聯系。
2. 應用內使用多進程可能導致哪些問題?
當一個APP啟用了多進程後,系統會為不同的進程分配不同的內存空間,因此所有需要通過內存共享的行為都會失敗。另外,還會導致以下幾個問題:
3. Android中有哪些進程間通信方式?
由於不同的進程擁有不同的數據空間,所以無論是應用內還是應用間,均無法通過共享內存來實現進程間通信。
進程和線程的主要區別(總結) - CSDN
線程和進程的區別是什麼? - 知乎
Android 多進程通信之幾個基本問題
面試題:IPC(跨進程通信)
㈡ 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多進程通信之 Binder
在 Linux 中一個進程空間可以分為 用戶空間 和 內核空間 ,不同的進程它們的用戶空間數據不可共享,但是它們的內核空間的數據可共享,即所有進程共用 1 個內核空間。進程內用戶空間和內核空間進行交互需通過系統調用。
Android 系統時基於 Linux 內核的,Linux 已經提供了多種 IPC 方式,如下:
所以,Android 為啥又單獨弄出一個 Binder 呢?主要有如下原因:
直觀地說,Binder 是 Android 中的一個類,它實現了 IBinder 介面;從 Android Framework 角度來說,Binder 是 ServiceManager 連接各種 Manager(ActivityManager、WindowManager...) 和相應 ManagerService 的橋梁;從 Android 應用層來說,Binder 是客戶端和服務端進行通信的媒介,當 bindService 的時候,服務端會返回一個包含了服務端業務調用的 Binder 對象,通過這個 Binder 對象,客戶端就可以獲取服務端提供的服務或者數據,這里的服務包括普通服務和基於 AIDL 服務。
Binder 定義了四個角色:Server,Client,ServiceManager 和 Bidner 驅動,其中 Server、Client、ServiceManager 運行於用戶空間,Binder 驅動運行於內核空間。
Binder 工作原理:
㈣ android開發中跨進程通信有幾種方式
Android進程間通信的幾種方式 定義多進程
第一:Android應用中使用多進程只有一個辦法(用NDK的fork來做除外),就是在AndroidManifest.xml中聲明組件時,用android:process屬性來指定。
不知定process屬性,則默認運行在主進程中,主進程名字為包名。
android:process = package:remote,將運行在package:remote進程中,屬於全局進程,其他具有相同shareUID與簽名的APP可以跑在這個進程中。
android:process = :remote ,將運行在默認包名:remote進程中,而且是APP的私有進程,不允許其他APP的組件來訪問。
第二:多進程引發的問題
靜態成員和單例失效:每個進程保持各自的靜態成員和單例,相互獨立。
線程同步機制失效:每個進程有自己的線程鎖。
SharedPreferences可靠性下降:不支持並發寫,會出現臟數據。
Application多次創建:不同進程跑在不同虛擬機,每個虛擬機啟動會創建自己的Application,自定義Application時生命周期會混亂。
綜上,不同進程擁有各自獨立的虛擬機,Application,內存空間,由此引發一系列問題。
第三: 進程間通信
Bundle/Intent傳遞數據:
可傳遞基本類型,String,實現了Serializable或Parcellable介面的數據結構。Serializable是Java的序列化方法,Parcellable是Android的序列化方法,前者代碼量少(僅一句),但I/O開銷較大,一般用於輸出到磁碟或網卡;後者實現代碼多,效率高,一般用戶內存間序列化和反序列化傳輸。
文件共享:
對同一個文件先後寫讀,從而實現傳輸,Linux機制下,可以對文件並發寫,所以要注意同步。順便一提,Windows下不支持並發讀或寫。
Messenger:
Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。
雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串列的,也就是說,Handler接到多個message時,就要排隊依次處理。
AIDL:
AIDL通過定義服務端暴露的介面,以提供給客戶端來調用,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能串列運行,所以Messenger一般用作消息傳遞。
通過編寫aidl文件來設計想要暴露的介面,編譯後會自動生成響應的java文件,伺服器將介面的具體實現寫在Stub中,用iBinder對象傳遞給客戶端,客戶端bindService的時候,用asInterface的形式將iBinder還原成介面,再調用其中的方法。
ContentProvider:
系統四大組件之一,底層也是Binder實現,主要用來為其他APP提供數據,可以說天生就是為進程通信而生的。自己實現一個ContentProvider需要實現6個方法,其中onCreate是主線程中回調的,其他方法是運行在Binder之中的。自定義的ContentProvider注冊時要提供authorities屬性,應用需要訪問的時候將屬性包裝成Uri.parse("content://authorities")。還可以設置permission,readPermission,writePermission來設置許可權。 ContentProvider有query,delete,insert等方法,看起來貌似是一個資料庫管理類,但其實可以用文件,內存數據等等一切來充當數據源,query返回的是一個Cursor,可以自定義繼承AbstractCursor的類來實現。
Socket:
學過計算機網路的對Socket不陌生,所以不需要詳細講述。只需要注意,Android不允許在主線程中請求網路,而且請求網路必須要注意聲明相應的permission。然後,在伺服器中定義ServerSocket來監聽埠,客戶端使用Socket來請求埠,連通後就可以進行通信。
㈤ android 進程間通信 rabbitmq
https://github.com/Harry-III/RabbitMQ-Android
上手了RabbitMQ?再來看看它的交換機(Exchange)吧
RabbitMQ的Java應用(1) -- Rabbit Java Client使用
RabbitMQ(三)入門 —— RabbitMQ的五種模式和四種交換機
本例子是改編自上面的github鏈接
1、android端不採用輪詢的方式請求伺服器,有點類似推送的感覺,能即時收到伺服器的信息
1、將rabbitmq放到單獨的進程中
2、重新定義一些方法
1、在多進程中通過 message.replyTo 方法將通信方式傳遞給 Service端
2、rabbitmq的管道創建是要在線程裡面,否則會報錯
3、如果有2個用戶都採用一個管道(管道名 A),當伺服器將信息都輸送到A管道後,哪個用戶處理消息快,哪個用戶得到的信息就多,所以最好就是每個用戶一個管道
本項目 github
RabbitMQClient .java
RabbitMQUtil .java
㈥ Android 進程間通信的幾種實現方式
Android 進程間通信的幾種實現方式
主要有4種方式:
這4種方式正好對應於android系統中4種應用程序組件:Activity、Content Provider、Broadcast和Service。
主要實現原理:
由於應用程序之間不能共享內存。為了在不同應用程序之間交互數據(跨進程通訊),AndroidSDK中提供了4種用於跨進程通訊的方式進行交互數據,實現進程間通信主要是使用sdk中提供的4組組件根據實際開發情況進行實現數據交互。
詳細實現方式:
Acitivity實現方式
Activity的跨進程訪問與進程內訪問略有不同。雖然它們都需要Intent對象,但跨進程訪問並不需要指定Context對象和Activity的 Class對象,而需要指定的是要訪問的Activity所對應的Action(一個字元串)。有些Activity還需要指定一個Uri(通過 Intent構造方法的第2個參數指定)。 在android系統中有很多應用程序提供了可以跨進程訪問的Activity,例如,下面的代碼可以直接調用撥打電話的Activity。
IntentcallIntent=newIntent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
Content Provider實現方式
Android應用程序可以使用文件或SqlLite資料庫來存儲數據。Content Provider提供了一種在多個應用程序之間數據共享的方式(跨進程共享數據)
應用程序可以利用Content Provider完成下面的工作
1. 查詢數據
2. 修改數據
3. 添加數據
4. 刪除數據
Broadcast 廣播實現方式
廣播是一種被動跨進程通訊的方式。當某個程序向系統發送廣播時,其他的應用程序只能被動地接收廣播數據。這就象電台進行廣播一樣,聽眾只能被動地收聽,而不能主動與電台進行溝通。在應用程序中發送廣播比較簡單。只需要調用sendBroadcast方法即可。該方法需要一個Intent對象。通過Intent對象可以發送需要廣播的數據。
Service實現方式
常用的使用方式之一:利用AIDL Service實現跨進程通信
這是我個人比較推崇的方式,因為它相比Broadcast而言,雖然實現上稍微麻煩了一點,但是它的優勢就是不會像廣播那樣在手機中的廣播較多時會有明顯的時延,甚至有廣播發送不成功的情況出現。
注意普通的Service並不能實現跨進程操作,實際上普通的Service和它所在的應用處於同一個進程中,而且它也不會專門開一條新的線程,因此如果在普通的Service中實現在耗時的任務,需要新開線程。
要實現跨進程通信,需要藉助AIDL(Android Interface Definition Language)。Android中的跨進程服務其實是採用C/S的架構,因而AIDL的目的就是實現通信介面。
總結
跨進程通訊這個方面service方式的通訊遠遠復雜於其他幾種通訊方式,實際開發中Activity、Content Provider、Broadcast和Service。4種經常用到,學習過程中要對沒種實現方式有一定的了解。