IPC機制1
1、Android IPC簡介
Inter-Process Communication的縮寫就是IPC,含義是進程間通信或是跨進程間通信,是指兩個進程進行交換數據的過程。
- 進程是什麽?
進程在pc上就是一個程序,在Android就是一個應用。線程表示的是cpu調度的最小單元,進程指一個執行單元。一個進程可包含多個線程,也可以只有一個線程。
所以Android IPC就可以理解為不同應用間的通信,但一個應用也有多進程模式,所以IPC不僅是應用間的通信,不過這個沒必要糾結,反正就是跨進程間通信。
2、Android中的多進程模式
- 開啟多線程模式
我們可以在AndroidManifest中修改Activity的屬性,輕易的開啟多線程模式。
<activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Main2Activity" android:process="com.xw.test" /> <activity android:name=".Main3Activity" android:process=":test" />
android:process指定這個屬性就可以開啟多進程模式,
將三個Activity依次啟動,然後使用adb shell可以看到
這是MainActivity運行在這個應用的默認進程中,進程名就是包名
這是Main2Activity運行在com.xw.test中
這是Main3Activity運行在com.example.administrator.test:test中
Main3Activity使用的“:”的含義是指要在當前的進程名之前附加上當前的包名。以“:”開頭的進程屬於當前應用的私有進程,其他應用的組件不可以和它跑在同一進程中,而不以“:”開頭的進程屬於全局進程,其他應用通過ShareUID方式可以和它跑在同一進程中。
Android系統會為每一個應用分配一個唯一的UID,具有相同UID的應用才能共享數據,兩個應用通過ShareUID方式可以跑在同一進程中還需要簽名相同,在這種情況下它們可以互相訪問對方的私有數據,比如data目錄、組件信息等。
- 多線程運行機制
如果新建一個類,這個類中有一個public的靜態成員變量,
public class Data { public static int Id = 1; }
然後我們在MainActivity的onCreate中將其賦值為2然後打印出來,然後我們再Main2Activity中直接打印出來。我們會發現原本應該是共享的靜態變量,MainActivity修改為2打印也是2,Main2Activity打印還是1.
其實,android會為每一個應用(或者說線程)分配一個獨立的虛擬機,不同的虛擬機在內存分配上有不同的地址空間,也就是說其實MainActivity和Main2Activity訪問的但是兩個名字相同的變量而已
一般來說,多進程會造成如下幾方面的問題:
(1) 靜態成員和單例模式失效:就上面的這種情況
(2) 線程同步機制完全失效:已經不是一塊內存了,所以無論是鎖對象還是鎖全局類都無法保證線程同步。
(3)SharePreferences的可靠性下降:SharePreferences的底層是通過讀/寫XML文件出現的,並發寫顯然是會出問題的,甚至並發讀/寫都有可能出現問題。
(4)Application會多次創建:當一個組件在跑一個新的進程的時候,分配獨立的虛擬機,其實就是啟動一個應用的過程,相當於系統把這個應用重啟了一遍,就創建了新的Application。
3、Binder
Binder是Android中的一個類,它實現了IBinder接口,Binder是Android中的一種跨進程通信方式
Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含服務端業務調用的Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務和數據。
這裏使用AIDL來分析Binder的工作機制,
先新建一個包並定義一個Book類,並實現Parcelable接口
public class Book implements Parcelable { public int bookId; public String bookName; public Book(int bookId, String bokName){ this.bookId = bookId; this.bookName = bookName; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeInt(bookId); parcel.writeString(bookName); } public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>(){ @Override public Book createFromParcel(Parcel parcel) { return new Book(parcel); } @Override public Book[] newArray(int i) { return new Book[i]; } }; private Book(Parcel parcel){ bookId = parcel.readInt(); bookName = parcel.readString(); } }View Code
然後再創建Book.aidl和IBookManager.aidl
//Book.aidl package com.xw.book.aidl; parcelable Book; //IBookManager.aidl package com.xw.book.aidl; import com.xw.book.aidl.Book; interface IBookManager{ List<Book> getBookList(); void addBook(in Book book); }
Book.aidl是Book在AIDL中的聲明,IBookManager.aidl是定義的一個接口。
再點擊安裝到手機之後,在gen目錄下的com.xw.book.aidl包中有一個IBookManager.java的類,這個是系統自動生成的
/* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\Users\\Administrator\\Desktop\\test\\app\\src\\main\\aidl\\com\\xw\\book\\aidl\\IBookManager.aidl */ package com.xw.book.aidl; public interface IBookManager extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.xw.book.aidl.IBookManager { private static final java.lang.String DESCRIPTOR = "com.xw.book.aidl.IBookManager"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.xw.book.aidl.IBookManager interface, * generating a proxy if needed. * */ public static com.xw.book.aidl.IBookManager asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.xw.book.aidl.IBookManager))) { return ((com.xw.book.aidl.IBookManager)iin); } return new com.xw.book.aidl.IBookManager.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.xw.book.aidl.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.xw.book.aidl.Book _arg0; if ((0!=data.readInt())) { _arg0 = com.xw.book.aidl.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.xw.book.aidl.IBookManager { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public java.util.List<com.xw.book.aidl.Book> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.xw.book.aidl.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.xw.book.aidl.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.xw.book.aidl.Book book) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((book!=null)) { _data.writeInt(1); book.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public java.util.List<com.xw.book.aidl.Book> getBookList() throws android.os.RemoteException; public void addBook(com.xw.book.aidl.Book book) throws android.os.RemoteException; }View Code
-
DESCRIPTOR
Binder的唯一標識,一般使用當前Binderd的類名表示。
- asInterface(android.os.IBinder obj)
用於將服務端的Binder對象轉換成客戶端需要的AIDL接口類型的對象,這種轉換是區分進程的,如果服務端和客戶端位於同一進程,那麽該方法會返回服務端的Stub對象本身,否則返回的是系統封裝後的Stub.proxy對象。
-
onTransact
這個方法運行在服務端的Binder線程池中,當客戶端發起跨進程請求時,遠程請求會通過系統底層封裝後交由此方法來處理, 服務端通過code可以確定客戶端請求的目標方法是什麽,從data中取出目標方法所需要的參數,然後執行目標方法沒目標方法執行完後,就向reply中寫入結果如果此方法返回false,那麽客戶端的請求就會失敗
- Proxy
這個類中有兩個方法分別是getBookList和addBook,兩個方法的執行過程是一樣的,說一個就行,方法將運行在客戶端,先創建該方法所需要的輸入型Parcel對象_data、輸出型Parcel對象_reply,和返回值對象,然後把該方法的參數信息寫入_data,然後調用transact方法來發起RPC(遠程過程調用)請求;然後服務端的onTransact方法會被調用,知道RPC過程返回後,當前線程繼續執行,並從_reply中取出RPC過程的返回結果,最後返回_reply中的結果
以上就是Binder的工作機制,然後還有兩點需要註意:當客戶端發出請求的時候,由於當前線程會被掛起直至服務端進程返回數據,所以如果一個遠程方法是很耗時的,那麽不能在UI線程中發起此遠程請求,其次,由於服務端的Binder方式運行在Binder的線程池中,所以Binder方法不管是否耗時都應該采用同步的方法去實現,因為它已經運行在一個線程中了。
Binder的工作機制
圖片來源:http://blog.csdn.net/u012827296/article/details/51259006
IPC機制1