Android的多進(jìn)程通訊-深入了解
一、多進(jìn)程是什么?
正常情況下,在Android系統(tǒng)中一個(gè)APP啟動(dòng)后只會(huì)運(yùn)行在一個(gè)進(jìn)程中,其進(jìn)程名為apk的包名,所有的組件都會(huì)在這個(gè)進(jìn)程中運(yùn)行;
但是如果需要將某些組件(如Service,Activity等)運(yùn)行在單獨(dú)的進(jìn)程中,就需要用到android:process屬性了。
我們可以給android的組件設(shè)置android:process屬性來使其運(yùn)行在指定的進(jìn)程中。
1、多進(jìn)程優(yōu)點(diǎn):
①使用更多的內(nèi)存
Android系統(tǒng)對(duì)每個(gè)應(yīng)用進(jìn)程的內(nèi)存占用是有限制的,而且占用內(nèi)存越大的進(jìn)程,通常被系統(tǒng)殺死的可能性越大。讓一個(gè)組件運(yùn)行在單獨(dú)的進(jìn)程中,可以減少主進(jìn)程所占用的內(nèi)存,避免OOM問題,降低被系統(tǒng)殺死的概率。
②實(shí)現(xiàn)多模塊
比如微信的小程序(一個(gè)住進(jìn)程,一個(gè)小程序進(jìn)程)、支付寶的小程序;
當(dāng)你啟動(dòng)一個(gè)小程序時(shí)候,就會(huì)啟動(dòng)小程序的進(jìn)程,不占用主進(jìn)程的內(nèi)存,使小程序進(jìn)程單獨(dú)出來,速度會(huì)快很多。
③子進(jìn)程奔潰,主進(jìn)程可以繼續(xù)工作
④主進(jìn)程退出,子進(jìn)程可以繼續(xù)工作
⑤實(shí)現(xiàn)守護(hù)進(jìn)程
通過JNI利用C/C++,調(diào)用fork()方法來生成子進(jìn)程,一般開發(fā)者會(huì)利用這種方法來做一些daemon(守護(hù)進(jìn)程)進(jìn)程,來實(shí)現(xiàn)防殺?;畹刃Ч?。
2、多進(jìn)程引起的問題
①靜態(tài)成員和單例模式失效
②線程同步機(jī)制失效
③SharedPreferences 可靠性降低
④Application 被多次創(chuàng)建
⑤多進(jìn)程交互麻煩
引起的原因:
Android中,系統(tǒng)會(huì)為每個(gè)應(yīng)用或進(jìn)程分配獨(dú)立的虛擬機(jī),不同的虛擬機(jī)自然占有不同的內(nèi)存地址空間,
所以同一個(gè)類的對(duì)象會(huì)產(chǎn)生不同的副本,導(dǎo)致共享數(shù)據(jù)失敗,必然也不能實(shí)現(xiàn)線程的同步。
二、多進(jìn)程通信方式
Android中支持的多進(jìn)程通信方式主要有以下幾種,它們之間各有優(yōu)缺點(diǎn),可根據(jù)使用場景選擇選擇:
- AIDL:功能強(qiáng)大,支持進(jìn)程間一對(duì)多的實(shí)時(shí)并發(fā)通信,并可實(shí)現(xiàn) RPC (遠(yuǎn)程過程調(diào)用)。
- Messenger:支持一對(duì)多的串行實(shí)時(shí)通信, AIDL 的簡化版本。
- Bundle:四大組件的進(jìn)程通信方式,只能傳輸 Bundle 支持的數(shù)據(jù)類型。
- ContentProvider:強(qiáng)大的數(shù)據(jù)源訪問支持,主要支持 CRUD 操作,一對(duì)多的進(jìn)程間數(shù)據(jù)共享,例如我們的應(yīng)用訪問系統(tǒng)的通訊錄數(shù)據(jù)。
- BroadcastReceiver:即廣播
廣播是一種被動(dòng)跨進(jìn)程通訊的方式。當(dāng)某個(gè)程序向系統(tǒng)發(fā)送廣播時(shí),其他的應(yīng)用程序只能被動(dòng)地接收廣播數(shù)據(jù)。
這就象電臺(tái)進(jìn)行廣播一樣,聽眾只能被動(dòng)地收聽,而不能主動(dòng)與電臺(tái)進(jìn)行溝通,在應(yīng)用程序中發(fā)送廣播比較簡單。
只需要調(diào)用sendBroadcast方法即可。該方法需要一個(gè)Intent對(duì)象。通過Intent對(duì)象可以發(fā)送需要廣播的數(shù)據(jù)
- 文件共享:在非高并發(fā)情況下共享簡單的數(shù)據(jù)。
- Socket:通過網(wǎng)絡(luò)傳輸數(shù)據(jù)。
這次介紹日常開發(fā)APP中常用的交互方式AIDL和Messenger
如圖
1、多進(jìn)程AIDL通信
AIDL是Android接口定義語言是用于定義服務(wù)器和客戶端通信接口的一種描述語言,可以使用它定義客戶端與服務(wù)端進(jìn)程間通信(IPC)的編程接口,
在 Android 中,進(jìn)程之間無法共享內(nèi)存(用戶空間),不同進(jìn)程之間的通信一般使用 AIDL 來處理。
使用簡單步驟:
創(chuàng)建一個(gè)AIDL文件(擴(kuò)展名為.aidl);
暴露一個(gè)接口給客戶端(通過建立一個(gè)Service,在onBind()方法中返回一個(gè)Stub類的實(shí)例);
服務(wù)端實(shí)現(xiàn)該AIDL文件生成的Java接口(系統(tǒng)會(huì)自動(dòng)生成對(duì)應(yīng)的Java接口);
客戶端連接綁定該遠(yuǎn)程服務(wù)。
①創(chuàng)建AIDL文件
創(chuàng)建一個(gè) AIDL 文件,聲明服務(wù)端要暴露給客戶端的接口,然后創(chuàng)建一個(gè) Service 監(jiān)聽客戶端的連接請(qǐng)求,并在其中實(shí)現(xiàn) AIDL 文件中的接口
注意,為了方便開發(fā),我們一般把 AIDL 相關(guān)的文件放在同一包中,這樣當(dāng)客戶端是另一個(gè)應(yīng)用時(shí)可方便的把整個(gè)包復(fù)制到客戶端工程中
首先了解下 AIDL 文件支持的幾種數(shù)據(jù)類型:
- 基本數(shù)據(jù)類型
- String、CharSequence
- ArrayList、HashMap,其內(nèi)部元素也需要被AIDL支持
- 實(shí)現(xiàn)了 Parcelable 接口的對(duì)象
- AIDL 類型的接口,非普通接口
Book是實(shí)現(xiàn)了Parcelable的類,只定義了name字段,按照規(guī)定如果 AIDL 文件用到了自定義Parcelable對(duì)象,同時(shí)需要提供一個(gè)Book.aidl文件
- package com.json;
- parcelable Book;
②ILibraryManager.aidl定義了服務(wù)端要暴露給客戶端的接口:
- package com.json;
- import com.json.Book;
- interface ILibraryManager{
- // 近期新書查詢
- List<Book> getNewBookList();
- // 圖書捐贈(zèng)
- void donateBook(in Book book);
- }
③接下來就是AIDL文件生成的Java接口,在編寫服務(wù)類前要先編譯項(xiàng)目,這樣在服務(wù)類里使用 AIDL 生成的java類
首先通過ILibraryManager.Stub()創(chuàng)建一個(gè)mBinder對(duì)象,并實(shí)現(xiàn)了ILibraryManager.aidl中定義的接口方法,在onBind()方法中返回創(chuàng)建的mBinder,并在服務(wù)onCreate()添加數(shù)據(jù)。
最后在 AndroidManifest.xml 注冊(cè)服務(wù):
- <service
- android:name=".ManagerService"
- android:process=":remote">
- </service>
- public class ManagerService extends Service {
- private static final String TAG = "ManagerService";
- // CopyOnWriteArrayList 支持并發(fā)讀寫
- private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
- private Binder mBinder = new ILibraryManager.Stub() {
- @Override
- public List<Book> getNewBookList() throws RemoteException {
- return mBookList;
- }
- @Override
- public void donateBook(Book book) throws RemoteException {
- mBookList.add(book);
- }
- };
- public LibraryManagerService() {
- }
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
- @Override
- public void onCreate() {
- super.onCreate();
- mBookList.add(new Book("book0"));
- mBookList.add(new Book("book1"));
- }
- }
④客戶端連接綁定該遠(yuǎn)程服務(wù)
先實(shí)現(xiàn)ServiceConnection接口,在onServiceConnected()方法中將IBinder對(duì)象轉(zhuǎn)換成ILibraryManager對(duì)象,通過該對(duì)象就能調(diào)用ILibraryManager.aidl中聲明的方法了。
接下來綁定服務(wù):
- public class AIDLActivity extends AppCompatActivity {
- private static final String TAG = "AIDLActivity";
- ILibraryManager libraryManager=null;
- private ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- libraryManager = ILibraryManager.Stub.asInterface(service);
- try {
- // test1
- List<Book> books = libraryManager.getNewBookList();
- Log.e(TAG, "books:" + books.toString());
- // test2
- libraryManager.donateBook(new Book("book" + books.size()));
- List<Book> books2 = libraryManager.getNewBookList();
- Log.e(TAG, "books:" + books2.toString());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- };
- void bindAidlData(){
- if(null==libraryManager){
- return;
- }
- try {
- // test1
- List<Book> books = libraryManager.getNewBookList();
- Log.e(TAG, "books:" + books.toString());
- // test2
- libraryManager.donateBook(new Book("book" + books.size()));
- List<Book> books2 = libraryManager.getNewBookList();
- Log.e(TAG, "books:" + books2.toString());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_aidl);
- bindNewService();
- }
- private void bindNewService() {
- Intent intent = new Intent(AIDLActivity.this, LibraryManagerService.class);
- bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
- }
- @Override
- protected void onDestroy() {
- unbindService(mServiceConnection);
- super.onDestroy();
- }
- }
2、aidl的通知功能
首先創(chuàng)建一個(gè)服務(wù)端通知客戶端的 IOnNewBookArrivedListener.aidl 接口:
- package com.json;
- import com.json.Book;
- interface IOnNewBookArrivedListener {
- void onNewBookArrived(in Book book);
- }
服務(wù)端要先注冊(cè)后才能收到通知,同時(shí)也可以取消注冊(cè),所以要給之前的ILibraryManager.aidl添加連個(gè)方法了:
- interface ILibraryManager{
- ......
- // 注冊(cè)通知
- void register(IOnNewBookArrivedListener listener);
- // 取消注冊(cè)
- void unregister(IOnNewBookArrivedListener listener);
- }
修改ManagerService:
- public class ManagerService extends Service {
- ......
- ......
- ......
- // 系統(tǒng)提供的專門用于保存、刪除跨進(jìn)程 listener 的類
- private RemoteCallbackList<IOnNewBookArrivedListener> mListenerList = new RemoteCallbackList<>();
- // AtomicBoolean 支持并發(fā)讀寫
- private AtomicBoolean mIsServiceDestroy = new AtomicBoolean(false);
- private Binder mBinder = new ILibraryManager.Stub() {
- ......
- @Override
- public void register(IOnNewBookArrivedListener listener) throws RemoteException {
- mListenerList.register(listener);
- Log.e(TAG, "register success");
- }
- @Override
- public void unregister(IOnNewBookArrivedListener listener) throws RemoteException {
- mListenerList.unregister(listener);
- Log.e(TAG, "unregister success");
- }
- };
- .......
- @Override
- public void onCreate() {
- super.onCreate();
- ......
- new Thread(new Runnable() {
- @Override
- public void run() {
- // 如果服務(wù)還沒終止
- while (!mIsServiceDestroy.get()) {
- try {
- Thread.sleep(10 * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- Book book = new Book("book" + mBookList.size());
- mBookList.add(book);
- bookArrivedNotify(book);
- }
- }
- }).start();
- }
- private void bookArrivedNotify(Book book) {
- int n = mListenerList.beginBroadcast();
- for (int i = 0; i < n; i++) {
- IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onNewBookArrived(book);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
- mListenerList.finishBroadcast();
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- mIsServiceDestroy.set(true);
- }
- }
這里用到了RemoteCallbackList類,它是系統(tǒng)提供的專門用于刪除跨進(jìn)程 listener 的類,用普通的集合難以保證客戶端注冊(cè)的 listener 和服務(wù)端存儲(chǔ)的 listener 是同一個(gè),會(huì)取消注冊(cè)失敗
客戶端代碼修改
- public class AIDLActivity extends AppCompatActivity {
- ......
- private ILibraryManager mLibraryManager;
- private Handler mHandler = new Handler(new Handler.Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_NEW_BOOK_ARRIVED:
- Log.e(TAG, "new book:" + msg.obj);
- break;
- }
- return true;
- }
- });
- private IOnNewBookArrivedListener listener = new IOnNewBookArrivedListener.Stub() {
- @Override
- public void onNewBookArrived(Book book) throws RemoteException {
- // 由于 onNewBookArrived 方法在子線程被調(diào)用,所以通過Handler切換到UI線程,方便UI操作
- mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, book).sendToTarget();
- }
- };
- private ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- ILibraryManager libraryManager = ILibraryManager.Stub.asInterface(service);
- mLibraryManager = libraryManager;
- try {
- ......
- // 注冊(cè)通知
- libraryManager.register(listener);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- ......
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_aidl);
- bindNewService();
- }
- @Override
- protected void onDestroy() {
- unbindService(mServiceConnection);
- if (mLibraryManager != null && mLibraryManager.asBinder().isBinderAlive()) {
- try {
- // 取消注冊(cè)
- mLibraryManager.unregister(listener);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- super.onDestroy();
- }
- }
3、Messenger通訊
Messenger 是一種輕量級(jí)的多進(jìn)程通信方式,它是在 AIDL 的基礎(chǔ)上封裝而成的,可以看做是 AIDL 的簡化版,支持一對(duì)多的串行實(shí)時(shí)通信,
一次只處理一個(gè)請(qǐng)求,不存在并發(fā)的問題。和 AIDL 的使用類似,但要簡單的多,同樣需要實(shí)現(xiàn)服務(wù)端和客戶端。
首先來看服務(wù)端
- public class MessengerService extends Service {
- private static final String TAG = "MessengerService";
- // 將Messenger和Handler關(guān)聯(lián)起來
- private Messenger mServiceMessenger = new Messenger(new MessengerHandler());
- public MessengerService() {
- }
- @Override
- public IBinder onBind(Intent intent) {
- return mServiceMessenger.getBinder();
- }
- private static class MessengerHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case MessengerActivity.MESSAGE_FROM_CLIENT:
- // 打印接收到的客戶端消息
- Log.e(TAG, "receive message from client:" + msg.getData().getString("msg"));
- // 給客戶端回復(fù)一條消息
- Messenger clientMessenger = msg.replyTo;
- Message message = Message.obtain();
- message.what = MessengerActivity.MESSAGE_FROM_SERVICE;
- Bundle bundle = new Bundle();
- bundle.putString("msg", "I am fine,thank you!");
- message.setData(bundle);
- try {
- clientMessenger.send(message);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- break;
- }
- }
- }
- }
看客戶端的實(shí)現(xiàn)
- public class MessengerActivity extends AppCompatActivity {
- private static final String TAG = "MessengerActivity";
- public static final int MESSAGE_FROM_CLIENT = 1;
- public static final int MESSAGE_FROM_SERVICE = 2;
- private Messenger mServiceMessenger;
- private Messenger mClientMessenger = new Messenger(new MessengerHandler());
- private ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mServiceMessenger = new Messenger(service);
- Message message = Message.obtain();
- message.what = MESSAGE_FROM_CLIENT;
- Bundle bundle = new Bundle();
- bundle.putString("msg", "how are you?");
- message.setData(bundle);
- // 傳遞服務(wù)端回復(fù)客戶端時(shí)需要使用的Messenger
- message.replyTo = mClientMessenger;
- try {
- mServiceMessenger.send(message);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_messenger);
- Intent intent = new Intent(MessengerActivity.this, MessengerService.class);
- bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
- }
- @Override
- protected void onDestroy() {
- unbindService(mServiceConnection);
- super.onDestroy();
- }
- private static class MessengerHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case MessengerActivity.MESSAGE_FROM_SERVICE:
- Log.e(TAG, "receive message from service:" + msg.getData().getString("msg"));
- break;
- }
- }
- }
- }
在onServiceConnected()中,將服務(wù)端的Binder轉(zhuǎn)換成服務(wù)端的Messenger對(duì)象,然后發(fā)送消息,由于服務(wù)端還需要給客服端回復(fù)消息,所以需要在客戶端創(chuàng)建一個(gè)Messenger對(duì)象附加在消息上發(fā)送給服務(wù)端使用
多進(jìn)程總結(jié):
1、多進(jìn)程app可以在系統(tǒng)中申請(qǐng)多份內(nèi)存,但應(yīng)合理使用,建議把一些高消耗但不常用的模塊放到獨(dú)立的進(jìn)程,不使用的進(jìn)程可及時(shí)手動(dòng)關(guān)閉;
2、多進(jìn)程占用內(nèi)存多,耗電量會(huì)增加,這個(gè)要注意;
3、每個(gè)進(jìn)程在創(chuàng)建的時(shí)候,都會(huì)執(zhí)行Application的onCreate進(jìn)行初始化,如果這時(shí)候沒有針對(duì)不同進(jìn)程處理,onCreate的初始化業(yè)務(wù)會(huì)被多次執(zhí)行,這是沒有必要的而且多次初始化容易引起問題,所以需根據(jù)不同進(jìn)程初始化相應(yīng)的業(yè)務(wù)。
本文轉(zhuǎn)載自微信公眾號(hào)「 Android開發(fā)編程」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 Android開發(fā)編程公眾號(hào)。