A. 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。
java">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種經常用到,學習過程中要對沒種實現方式有一定的了解。
B. Android:AIDL進程間通信基本框架
在某些業務場景下,我們需要在應用中單獨開啟一個進程進行一些操作。比如性能監控,如果讓原始業務和性能監控本身的業務跑在同一個進程下,那麼就會導致性能統計的數據的失真。
而進程間通信,一般採用AIDL機制的客戶端與服務端通信。
AIDL只能傳遞如下幾類數據:
當傳遞自定義 Parcelable 時,有三處地方需要注意:
當傳遞其他 aidl 介面時,同樣必須要 import 這個 aidl 文件
編寫完 aidl 文件後,make一下工程,會在 build 下的 generated 下的 source 下的 aidl 目錄生成對應的介面類文件。aidl 介面其實就是 API 介面,通過實現對應介面類的 Stub 子類來實現具體的 API 邏輯;通過對應介面類的 Stub 子類的 asInterface 方法得到具體的實現類,調用具體的 API 方法。
一個基本的客戶端服務端的通信結構一般包括如下功能
客戶端的功能
服務端的功能
客戶端的相關功能實現比較簡單,麻煩的是服務端的功能。因為 AIDL 介面定義的都是服務端的介面,是由客戶端來調用的。而想要實現服務端反向調用客戶端則需要通過其他手段實現。
想要實現服務端主動連接客戶端,最好的辦法就是 服務端發送廣播,客戶端收到廣播後再主動連接服務端 ,通過這種方式變相地實現服務端主動連接客戶端的功能
想要實現服務端主動斷開客戶端,除了上面 發送廣播是一種實現方式外,還可以通過 android 的系統API RemoteCallbackList,用包名作為key值來注冊遠程回調介面的方式,讓服務端持有客戶端的回調介面,服務端調用回調介面,客戶端在回調介面中實現主動斷開服務端 ,通過這種方式變數地實現服務端主動斷開客戶端的功能。而採用後者會顯得更加優雅
既然所有的操作歸根結底都是由客戶端來完成的,那麼客戶端必須得有如下的功能模塊:
服務端必須得有的功能模塊:
那麼,整體的通信流程就是如下的步驟:
首先是通信的 aidl 介面定義
然後是客戶端的連接操作與斷開連接操作,包括廣播接收者的注冊以及回調介面的實現
然後是客戶端的拉取數據和推送數據操作
接著是服務端的 iBinder 介面的實現,完成回調介面的注冊、業務子線程的開啟和關閉、數據的推送和數據的拉取操作
然後是服務端的主動連接和主動斷開連接操作
最後是服務端的 onUnbind 方法的實現,對回調介面進行反注冊
服務端模仿 FloatViewPlugin 自定義插件,實現 IServicePlugin 介面,定製個性化的懸浮窗插件
客戶端在 Appliaction 的 onCreate方法中初始化
在 MainActivity 上實現連接、斷開、數據通信
C. 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開發藝術探索》
D. 利用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方法只能傳遞消息,不能跨進程調用方法
E. 如何在Android中使用AIDL設計遠程介面麻煩告訴我
在Android平台,一個進程通常不能訪問另一個進程的內存空間,所以要想對話,需要將對象分解成操作系統可以理解的基本單元,並且有序地通過進程邊界。
通過代碼來實現這個數據傳輸過程是冗長乏味的,Android提供了AIDL工具來處理這項工作。AIDL()是一種IDL語言,用於生成可以在Android設備上兩個進程之間進行進程間通信(IPC)的代碼。如果在一個進程中(例如Activity)要調用另一個進程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數。AIDLIPC機制是面向介面的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞數據。
一、使用AIDL實現IPC(ImplementingIPCUsingAIDL)
使用AIDL實現IPC服務的步驟是:第一,創建.aidl文件。該文件(YourInterface.aidl)定義客戶端可用的方法和數據介面。第二,在makefile文件中加入.aidl文件(Eclipse中的ADT插件提供管理功能)。Android包括名為AIDL的編譯器,位於tools/文件夾。第三,實現介面-AIDL編譯器從AIDL介面文件中利用Java語言創建介面。該介面有一個繼承的命名為Stub的內部抽象類(已實現一些IPC調用的附加方法),要做的就是創建一個繼承於YourInterface.Stub的類,並且實現在.aidl文件中聲明的方法。第四,向客戶端公開介面。如果是編寫服務,應該繼承Service並且重載Service.onBind(Intent)以返回實現了介面的對象實例。
二、創建.aidl文件(Createan.aidlFile)
AIDL使用簡單的語法來聲明介面,描述其方法以及方法的參數和返回值。這些參數和返回值可以是任何類型,甚至是其他AIDL生成的介面。需要注意的是,必須導入所有非內置類型。AIDL能支持的數據類型有以下幾類:第一,Java編程語言的主要類型(int,boolean等),不需要import語句。第二,通常引引用方式傳遞的其他AIDL生成的介面,必須要import語句聲明。第三,實現了Parcelableprotocol以及按值傳遞的自定義類,必須要import語句聲明。另外,還有一些不需要import語句,如String等。
三、實現介面(ImplementingtheInterface)
AIDL生成了與.aidl文件同名的介面,如果使用Eclipse插件,AIDL會作為編譯碰歷過程的一部分自動運行(不需要先運行AIDL再編譯項目);如果沒有插件,就要先運行AIDL。
生成的介麵包含一個名為Stub的抽象的內部類,該類聲明了所有.aidl中描述的方法,Stub還定義了少量的輔助方法,尤其是asInterface(),通過它獲得IBinder(當applicationContext.bindService()成功調用時傳遞到客戶端的onServiceConnected())並且返回用於調用IPC方法的介面實例。要實現自己的介面,就從YourInterface.Stub類繼承,然笑蠢搜後實現相關方法(可以創建.aidl文件實現stub方法而不用在中間編譯,Android編譯過程會在.java文件之前處理.aidl文件)。
在完成了介面的實現後,需要向客戶端暴露介面,也就是發布服務。實現的方法是繼承Service,然後檔知實現以Service.onBind(Intent)返回一個實現了介面的類對象。下面的代碼片斷表示了暴露IRemoteService介面給客戶端的方式。如果有類想要能過AIDL在進程之間傳遞,這一想法是可以實現的,但必須確保這個類在IPC的兩端的有效性。
以上是筆者對《Android中使用AIDL設計遠程介面》的一些思路與實現方法。筆者認為,由於Android自身的集成性、控制性、交互性等特點,可以激發學生的學習的興趣,調動學生的積極參與,擴大學生知識面,提供多種學習的路徑。
(作者單位:鎮江技師學院)
F. android 進程間的通信(IPC)方式有哪些
Android是基於linux內核的。所以linux支持的IPC,android都用到了。比如命名管道,共享內存。 除此外,android還使用了一套自己獨特的IPC方式 binder. 主要用於2個進程間的遠程調用。但是這里就牽扯遠程調用如何傳遞參數,如何回傳結果。 這需要調用者對數據進行打包和解包,是一個繁瑣的過程。為此,android引入了aidl(android interface description launguage). 開發人員定義好aidl,android會根據aidl的描述生產stub代碼,幫助調用者對數據打包,解包。開發人員所要做的事是繼承stub代碼,實現stub代碼中的函數。這些函數是你在aidl中定義的。
G. Android進程間和線程間通信方式
進程:是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
線程:是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一些在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。
區別:
(1)、一個程序至少有一個進程,一個進程至少有一個線程;
(2)、線程的劃分尺度小於進程,使得多線程程序的並發性高;
(3)、進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉。
---------------------
一、Android進程間通信方式
1.Bundle
由於Activity,Service,Receiver都是可以通過Intent來攜帶Bundle傳輸數據的,所以我們可以在一個進程中通過Intent將攜帶數據的Bundle發送到另一個進程的組件。
缺點:無法傳輸Bundle不支持的數據類型。
2.ContentProvider
ContentProvider是Android四大組件之一,以表格的方式來儲存數據,提供給外界,即Content Provider可以跨進程訪問其他應用程序中的數據。用法是繼承ContentProvider,實現onCreate,query,update,insert,delete和getType方法,onCreate是負責創建時做一些初始化的工作,增刪查改的方法就是對數據的查詢和修改,getType是返回一個String,表示Uri請求的類型。注冊完後就可以使用ContentResolver去請求指定的Uri。
3.文件
兩個進程可以到同一個文件去交換數據,我們不僅可以保存文本文件,還可以將對象持久化到文件,從另一個文件恢復。要注意的是,當並發讀/寫時可能會出現並發的問題。
4.Broadcast
Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播。
5.AIDL方式
Service和Content Provider類似,也可以訪問其他應用程序中的數據,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫AIDL服務。
AIDL通過定義服務端暴露的介面,以提供給客戶端來調用,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能串列運行,所以Messenger一般用作消息傳遞。
6.Messenger
Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。
雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串列的,也就是說,Handler接到多個message時,就要排隊依次處理。
7.Socket
Socket方法是通過網路來進行數據交換,注意的是要在子線程請求,不然會堵塞主線程。客戶端和服務端建立連接之後即可不斷傳輸數據,比較適合實時的數據傳輸
二、Android線程間通信方式
一般說線程間通信主要是指主線程(也叫UI線程)和子線程之間的通信,主要有以下兩種方式:
1.AsyncTask機制
AsyncTask,非同步任務,也就是說在UI線程運行的時候,可以在後台的執行一些非同步的操作;AsyncTask可以很容易且正確地使用UI線程,AsyncTask允許進行後台操作,並在不顯示使用工作線程或Handler機制的情況下,將結果反饋給UI線程。但是AsyncTask只能用於短時間的操作(最多幾秒就應該結束的操作),如果需要長時間運行在後台,就不適合使用AsyncTask了,只能去使用Java提供的其他API來實現。
2.Handler機制
Handler,繼承自Object類,用來發送和處理Message對象或Runnable對象;Handler在創建時會與當前所在的線程的Looper對象相關聯(如果當前線程的Looper為空或不存在,則會拋出異常,此時需要在線程中主動調用Looper.prepare()來創建一個Looper對象)。使用Handler的主要作用就是在後面的過程中發送和處理Message對象和讓其他的線程完成某一個動作(如在工作線程中通過Handler對象發送一個Message對象,讓UI線程進行UI的更新,然後UI線程就會在MessageQueue中得到這個Message對象(取出Message對象是由其相關聯的Looper對象完成的),並作出相應的響應)。
三、Android兩個子線程之間通信
面試的過程中,有些面試官可能會問Android子線程之間的通信方式,由於絕大部分程序員主要關注的是Android主線程和子線程之間的通信,所以這個問題很容易讓人懵逼。
主線程和子線程之間的通信可以通過主線程中的handler把子線程中的message發給主線程中的looper,或者,主線程中的handler通過post向looper中發送一個runnable。但looper默認存在於main線程中,子線程中沒有Looper,該怎麼辦呢?其實原理很簡單,把looper綁定到子線程中,並且創建一個handler。在另一個線程中通過這個handler發送消息,就可以實現子線程之間的通信了。
子線程創建handler的兩種方式:
方式一:給子線程創建Looper對象:
new Thread(new Runnable() {
public void run() {
Looper.prepare(); // 給這個Thread創建Looper對象,一個Thead只有一個Looper對象
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
Looper.loop(); // 不斷遍歷MessageQueue中是否有消息
};
}).start();
---------------------
方式二:獲取主線程的looper,或者說是UI線程的looper:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper()){ // 區別在這!!!
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();
---------------------