❶ android進階-AIDL之介面注冊/解注冊
AIDL-基本使用
AIDL-自定義數據類型
AIDL-修飾符in,out,inout
AIDL-重連方法
AIDL-介面注冊/解注冊
AIDL-連接池
為什麼要特意講解一下介面的注冊與取消注冊呢,因為在使用AIDL進程跨進程通信的時候, 每次傳遞的介面對象在內存中的地址都是不一樣的 ,所以在注冊了之後,無法使用常規的方式去取消, 因為注冊和解注冊傳遞的介面地址都不一樣 ,系統無法識別
由於上面的問題,AIDL中提供了一個專門解決上述情況的類 RemoteCallbackList ,其工作原理就是:
首先,在前面講解 AIDL的基本使用 的基礎上先增加新的AIDL介面以及注冊和解注冊方法:
然後就是 RemoteCallbackList 的使用方法了:
注冊/解注冊很簡單
接著是使用介面的方式:
ps: 需要注意的是 beginBroadcast() 方法和 finishBroadcast() 方法 必須配合使用 ,哪怕只是簡單的獲取集合大小
使用AIDL進行跨進程間通信中,往往我們是需要注冊監聽,讓服務端通知的,但是服務端也必須提供解注冊的方法,不然客戶端如果離開某個界面不想再接受消息了,雖然直接離開不做處理客戶端這邊不會出錯,但是服務端那邊的監聽集合還存在之前的,那麼就會浪費系統資源,所以有注冊監聽的時候,最好也要實現解注冊的方法
https://github.com/returntolife455/DemoList
《Android開發藝術探索》
❷ Android開發中在哪些場合下會需要使用AIDL
嚴格來說,線程是共享資源的,所以線程之間是不存在通信的,Android裡面的Handle是用來解決非同步調用的,這個觀念很重要,想明白了,代碼也就寫的更合理了。
進程之間內存等資源是隔離的,而AIDL,是Android提供的跨進程通信IPC工具Binder的具體使用方法,跟其他Linux跨進程通信(socket,管道,能存共享等)在概念上沒啥差。所以要實現跨進程的內存訪問(比如數據傳輸,函數跨進程同步調用等)就需要了AIDL了,當然了AIDL並不是Android中跨進程通信的唯一選擇,socket(systemServer進程與zygote進程,pkms調用install進程,MountService與vold進程通信都是通過socket),共享內存(sqlite3查詢就用了)等都可以用的,但是沒有Binder通過AIDL好用罷了。
❸ 安卓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中的所有元素必須是此列表中支持的數據類型)
介面里的方法就是按需求需創建。這里只舉幾個簡單的示例。
❹ 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開發藝術探索讀書筆記之AIDL
AIDL是 Android Interface definition language的縮寫,一看就明白,它是一種android內部進程通信介面的描述語言,通過它我們可以定義進程間的通信介面
AIDL可以實現跨進程的方法調用。定義進程通信介面供服務端和客戶端調用。
在AIDL文件中並不是所有數據類型都可以使用。只支持下列數據類型
默認情況下AIDL的調用過程是同步的,所以不能直接進行比較耗時的操作,否則容易導致客戶端ANR。如果需要進行非同步操作,在服務端不需要另起線程,但是在客戶端需要另起線程訪問遠程方法,再通過Handler通知到UI線程即可!
❻ 利用Messenger跨進程通信
Android筆記多進程通信之利用Messenger跨進程通信,
提起跨進程通信,大多數人首先會想到AIDL,AIDL,中文名稱是android介面描述語言,是android系統中用於進行跨進程通信必須了解的。其實messenger和AIDL作用一樣,都可以進行進程間通訊。它是基於消息的進程間通信,通過構建Message來在客戶端和服務端之間傳遞數據,就像Handler發送消息在子線程和UI線程發送消息那樣,還不用去寫AIDL文件。
Messenger翻譯為信使,可以在不同進程中傳遞Message對象,在Message中放入我們需要傳遞的信息,然後通過Messenger將Message傳遞給對方,就可以輕輕鬆鬆實現跨進程數據傳遞。實際上Messenger是一種輕量級的IPC(跨進程通信)方式,它的底層仍然是實現的AIDL。
此外,還支持記錄客戶端對象的Messenger,然後可以實現一對多的通信;甚至作為一個轉接處,任意兩個進程都能通過服務端進行通信。
相同點:
1.都與IPC的調用有關;
2.Messenger 是一種輕量級的 IPC方案,底層實現了AIDL,只是進行了封裝,開發的時候不用寫.aidl文件。
3.都支持實時通信;
不同點:
1. Messenger一次只能處理一個請求(串列)/AIDL一次可以處理多個請求(並行);
當您需要執行 IPC 時,為您的介面使用 Messenger 要比使用 AIDL 實現更加簡單,因為 Messenger 會將所有服務調用排入隊列,而純粹的 AIDL 介面會同時向服務發送多個請求,服務隨後必須應對多線程處理。
對於大多數應用,服務不需要執行多線程處理,因此使用 Messenger 可讓服務一次處理一個調用。如果您的服務必須執行多線程處理,則應使用 AIDL 來定義介面。
2. Messenger不支持RPC,只能通過message傳遞消息/AIDL支持RPC;
3. Messenger使用簡單,輕量級,不需要創建AIDL文件/AIDL使用復雜,需要創建AIDL文件;
服務端:
1.創建一個handler對象,並實現hanlemessage方法,用於接收來自客戶端的消息,並作處理
2.創建一個messenger,封裝handler
3.用messenger的getBinder()方法獲取一個IBinder對象,通過onBind返回給客戶端
客戶端:
1.在activity中綁定服務
2.創建ServiceConnection並在其中使用 IBinder 將 Messenger實例化
3.使用Messenger向服務端發送消息,或需要伺服器端返回消息,需要創建一個messenger,封裝handler,並將這個messenger傳遞給伺服器端。在handler中接收伺服器消息。這樣就實現了客戶端和服務端的雙向通信了。
4.解綁服務
5.服務端中在 handleMessage() 方法中接收每個 Message
創建一個service
注冊service,當然要設置在不同的進程
注意:Service在聲明時必須對外開放,即android:exported="true"
客戶端是通過綁定服務端返回的binder來創建Messenger對象,並通過這個Messenger對象來向服務端發送消息。
總結
Message中的Bundle支持多種數據類型,replyTo欄位用於傳輸Messager對象,以便進程間相互通信
Messager以串列的方式處理客戶端發來的消息,不適合有大量並發的請求
Messager方法只能傳遞消息,不能跨進程調用方法
❼ 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開發aidl何時使用
1.什麼是aidl:aidl是 Android Interface definition language的縮寫,一看就明白,它是一種android內部進程通信介面的描述語言,通過它我們可以定義進程間的通信介面
icp:interprocess communication :內部進程通信
2.既然aidl可以定義並實現進程通信,那麼我們怎麼使用它呢?文檔/android-sdk/docs/guide/developing/tools/aidl.html中對步驟作了詳細描述:
--1.Create your .aidl file - This file defines an interface (YourInterface.aidl) that defines the methods and fields available to a client.
創建你的aidl文件,我在後面給出了一個例子,它的aidl文件定義如下:寫法跟java代碼類似,但是這里有一點值得注意的就是它可以引用其它aidl文件中定義的介面,但是不能夠引用你的java類文件中定義的介面
package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.AIDLActivity;
interface AIDLService {
void registerTestCall(AIDLActivity cb);
void invokCallBack();
}
--2.Add the .aidl file to your makefile - (the ADT Plugin for Eclipse manages this for you). Android includes the compiler, called AIDL, in the tools/ directory.
編譯你的aidl文件,這個只要是在eclipse中開發,你的adt插件會像資源文件一樣把aidl文件編譯成java代碼生成在gen文件夾下,不用手動去編譯:編譯生成AIDLService.java如我例子中代碼
--3.Implement your interface methods - The AIDL compiler creates an interface in the Java programming language from your AIDL interface. This interface has an inner abstract class named Stub that inherits the interface (and implements a few additional methods necessary for the IPC call). You must create a class that extends YourInterface.Stub and implements the methods you declared in your .aidl file.
實現你定義aidl介面中的內部抽象類Stub,public static abstract class Stub extends android.os.Binder implements com.cao.android.demos.binder.aidl.AIDLService
Stub類繼承了Binder,並繼承我們在aidl文件中定義的介面,我們需要實現介面方法,下面是我在例子中實現的Stub類:
private final AIDLService.Stub mBinder = new AIDLService.Stub() {
@Override
public void invokCallBack() throws RemoteException {
Log("AIDLService.invokCallBack");
Rect1 rect = new Rect1();
rect.bottom=-1;
rect.left=-1;
rect.right=1;
rect.top=1;
callback.performAction(rect);
}
@Override
public void registerTestCall(AIDLActivity cb) throws RemoteException {
Log("AIDLService.registerTestCall");
callback = cb;
}
};
Stub翻譯成中文是存根的意思,注意Stub對象是在被調用端進程,也就是服務端進程,至此,服務端aidl服務端得編碼完成了。
--4.Expose your interface to clients - If you're writing a service, you should extend Service and override Service.onBind(Intent) to return an instance of your class that implements your interface.
第四步告訴你怎麼在客戶端如何調用服務端得aidl描述的介面對象,doc只告訴我們需要實現Service.onBind(Intent)方法,該方法會返回一個IBinder對象到客戶端,綁定服務時不是需要一個ServiceConnection對象么,在沒有了解aidl用法前一直不知道它是什麼作用,其實他就是用來在客戶端綁定service時接收service返回的IBinder對象的:
AIDLService mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log("connect service");
mService = AIDLService.Stub.asInterface(service);
try {
mService.registerTestCall(mCallback);
} catch (RemoteException e) {
}
}
public void onServiceDisconnected(ComponentName className) {
Log("disconnect service");
mService = null;
}
};
mService就是AIDLService對象,具體可以看我後面提供的示例代碼,需要注意在客戶端需要存一個服務端實現了的aidl介面描述文件,但是客戶端只是使用該aidl介面,不需要實現它的Stub類,獲取服務端得aidl對象後mService = AIDLService.Stub.asInterface(service);,就可以在客戶端使用它了,對mService對象方法的調用不是在客戶端執行,而是在服務端執行。
4.aidl中使用java類,需要實現Parcelable介面,並且在定義類相同包下面對類進行聲明:
上面我定義了Rect1類
之後你就可以在aidl介面中對該類進行使用了
package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.Rect1;
interface AIDLActivity {
void performAction(in Rect1 rect);
}
注意in/out的說明,我這里使用了in表示輸入參數,out沒有試過,為什麼使用in/out暫時沒有做深入研究。
轉載