IPC機制簡介
IPC是Inter-Process Communication的縮寫,含義就是跨進程通信。
首先我們要理解什么是進程,什么是線程。按操作系統的描述,進程是資源分配的最小單位,而線程是CPU調度的最小單位,一個進程可以包含多個線程(主線程、子線程)。多線程需要考慮并發問題。
Android中的主線程是也叫UI線程,在主線程執行耗時操作會ANR
多進程的兩種情況
1 某個應用由于自身原因需要采用多進程模式來實現(如:某些模塊由于特殊原因需要運行在獨立進程)
2 為了加大一個應用可使用的內存通過多進程來獲取多份內存空間
Android中的多進程模式
在正式講解進程間通信前我們先了解Android中的多進程模式。
通過給四大組件指定android:process屬性可以輕易開啟多進程(看起來簡單,但是有許多需要注意的問題)
一般情況下Android中多進程是指一個應用中存在多個進程的情況。首先在Android使用多進程只有一中方式就是為四大組件指定android:process屬性(特例:使用JNI在native底層fork一個新進程)
1 android:process=”:test” (私有進程其他應用組件不可在該進程)
2 android:process=”com.test.l” (全局進程其他組件可用ShareUID方式跑在相同進程中)
UID:在Linux中的代表用戶ID,android系統為每個應用分配的標識,也就是說android中的每個應用其實就相當于一個用戶。兩個應用如果想通過shareUID的方式跑在同一個進程中必須保證UID相同,并且簽名一致。那么同進程中就可以相互訪問對方的私有數據(如data,res資源,組件信息,內存數據等等)
ShareUID擴展
通過shareduserid來獲取系統權限
(1)在AndroidManifest.xml中添加android:sharedUserId=”android.uid.system”
(2)在Android.mk文件里面添加LOCAL_CERTIFICATE := platform(使用系統簽名)
(3)在源碼下面進行mm編譯
這樣生成的apk能夠獲取system權限,可以在任意system權限目錄下面進行目錄或者文件的創建,以及訪問其他apk資源等(注意創建的文件(夾)只有創建者(比如system,root除外)擁有可讀可寫權限
運行機制與IPC基礎
首先我們知道Android系統是基于JVM(Dalvik與ART)
其次系統會為每個進程分配一個獨立的虛擬機,意味著進程間的內存的相互獨立的
一般來說使用多進程會有幾個問題
1 靜態成員與單利模式完全失效
2 線程同步機制完全失效
3 SP可靠性下降
4 Application創建多次
問:進程間的對象傳遞問題怎么解決?
通過IBinder來實現進程間對象的轉換
IPC基礎概念介紹
主要包含三部分:Serialiazable,Parcelable以及Binder
序列化:將對象轉化為字節的過程
Serialiazable:Java提供的序列化接口(標記接口)
Parcelable:android提供的序列化接口
Serialiazable與Parcelable的區別:Serialiazable使用簡單但是需要大量I/O操作,Parcelable使用較繁瑣,主要用于內存序列化,效率高
Binder
直觀的看,Binder是Android中的一個類,實現了IBinder接口
從不同角度理解Binder:
1 從IPC角度,Binder是跨進程通信方式
2 從FrameWork角度,Binder是ServiceManager連接各種Manager(如am,wm等)的橋梁
3 從應用層角度,Binder是客戶端與服務端通信的媒介
AIDL的初步了解
1 創建Book.java實體類(實現Parcelable接口,支持內存序列化)
2 創建Book類的aidl聲明
3 創建IBookManager的aidl接口
實現Parcelable接口的Book類
public class Book implements Parcelable{
private int id;
private String name;
private double price;
public Book(int id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public Book() {
}
protected Book(Parcel in) {
id = in.readInt();
name = in.readString();
price = in.readDouble();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(id);
parcel.writeString(name);
parcel.writeDouble(price);
}
}
其實內部是通過Parcel進行對象的轉換的,咱們順便看看Parcel類的描述
Container for a message (data and object references) that can
be sent through an IBinder. A Parcel can contain both flattened data
that will be unflattened on the other side of the IPC (using the various
methods here for writing specific types, or the general
{@link Parcelable} interface), and references to live {@link IBinder}
objects that will result in the other side receiving a proxy IBinder
connected with the original IBinder in the Parcel.
簡單的翻譯下,Parcel是IBinder發送消息(數據和對象引用)的容器,Parcel可以數據通過各個操作基礎類型的方法將數據轉化為扁平化傳遞給IPC的另一端,并且通過IBinder使得對方收到的代理IBinder對象中包裹著原始IBinder。總的說它的作用就是實現對象數據在內存中的傳遞
Book的aidl聲明
package com.example.pangyunxiao.ipcdemo.com.itszt.l;
parcelable Book;
我用的IDE是Android Studio,直接右鍵創建aidl文件。會自動幫你創建aidl目錄,并且將你創建的aidl聲明放置到你的項目包名下,如果的eclipse則開發者要自行注意。
IBookManager的聲明
package com.example.pangyunxiao.ipcdemo.com.itszt.l;
import com.example.pangyunxiao.ipcdemo.com.itszt.l.Book;
import com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener;
// Declare any non-default types here with import statements
interface IBookManager {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
void addBook(in Book book);
List<Book> getBooks();
void addBookAndNotify(in Book book);
void registerListener(IOnNewBookAddedListener l);
void unregisterListener(IOnNewBookAddedListener l);
}
注意問題
1 實體類的包名與aidl文件的包名必須一致
2 IBookManager中必須import所需實體類
3 接口中聲明的方法參數需要使用in/out/inout
4 aidl文件以及實體類在兩端都要有,并且同個包下
IBookManager.java簡析
接著咱們編譯一下項目,會發現自動生成的IBookManager.java類。路徑:eclipse中位于gen目錄下,as中位于build\generated\source\aidl\debug目錄下,接著咱們來簡要分析下這個類(由于類比長,就不把代碼全貼出來啦)
public interface IBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager interface,
* generating a proxy if needed.
*/
public static com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager asInterface(android.os.IBinder 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 {
...
}
private static class Proxy implements com.example.pangyunxiao.ipcdemo.com.itszt.l.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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
...
}
@Override
public void addBook(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException {
...
}
@Override
public java.util.List<com.example.pangyunxiao.ipcdemo.com.itszt.l.Book> getBooks() throws android.os.RemoteException {
...
}
@Override
public void addBookAndNotify(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException {
...
}
@Override
public void registerListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException {
...
}
@Override
public void unregisterListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException {
...
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_addBookAndNotify = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
public void addBook(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException;
public java.util.List<com.example.pangyunxiao.ipcdemo.com.itszt.l.Book> getBooks() throws android.os.RemoteException;
public void addBookAndNotify(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException;
public void registerListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException;
public void unregisterListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException;
}
DESCRIPTOR:Binder的唯一標識
1 這是個接口類并且集成了IInterface接口,所有可以在Binder中傳輸的接口都需要繼承IIterface接口
2 Stub內部類:是IBookManager類的內部類,就是一個Binder類
asInterface 靜態方法:Binder對象轉換為接口類型對象
asBinder 非靜態方法:接口類型對象轉換為Binder對象
onTransact方法:當客戶端發起遠程調用時,在服務端會執行該方法;參數code:標識調用的方法;參數data:傳遞的參數;參數reply:用于存儲返回值;該方法返回值是boolean表示遠程調用是否成功(可做權限驗證)
3 Proxy:Stub的內部類,作用是作為IBookManager的代理類(asInterface返回的其實就是它);在該類中主要實現了各個方法的執行流程。例如addBook:方法運行在客戶端,首先獲取兩個Parcel對象(參數_data與返回值_reply),然后把參數信息寫入_data中,調用IBinder對象的transact方法發起遠程調用,此時當前線程被掛起然后服務器端的onTransact執行,當執行完畢,當前線程繼續執行,如果方法有返回值的話通過_reply取得。
注意點
當客戶端發起請求時當前線程會被掛起直至服務端返回數據。那么如果一個遠程方法是耗時的就不能在UI線程發起遠程請求
2 AIDL文件并不是必須的,只是為了方便系統根據aidl文件生存java類,我們可以拋開aidl文件直接寫一個Binder
(1創建IBookManager接口類2IBookManager實現類3 Servic中返回)
3 Binder運行在服務端進程,如果服務器進程由于某種原因終止了,那么遠程調用將失敗(稱為Binder死亡),可以通過Binder對象的linkToDeath方法設置死亡代理
實現IPC的方式
怎么實現IPC?其實只要完成它的本質需求,就是在進程之間傳遞數據,那就算實現了IPC。因此我們有很多種方式可以完成這個目標。實際開發過程中可以選擇合適的方式去實現這個數據傳遞過程。
1 使用Bundle
這是最簡單的方式,它就是通過Bundle在不同進程的組件之間傳遞數據
startActivity(new Intent(...).putExtra("data",bundle));
2 使用文件共享
利用多進程同時讀寫同個外部文件達到是數據交互的目的
存儲形式沒有限制:xml,文本,對象序列化等等
缺點:由于Linux系統對文件并發讀寫沒有限制,會導致數據不同步問題,所以該方式只適合于對數據同步要求不高的進程間通信
3 使用共享參數
共享參數是android中一中輕量級存儲方案,底層用實現xml文件,系統對它的讀寫有一定的緩存策略(內存中會有一份sp的備份)在多進程模式下,系統對它的讀/寫是不可靠的,高并發讀/寫時有可能會丟失數據
4 使用Messenger
Messenger(信使):在不同的進程之間傳遞Message對象,是一種輕量級的IPC方案,底層實現就是AIDL
客戶端使用服務器的messenger向服務器發消息
服務器使用客戶端的messenger向客戶端發消息
(類似Handler的使用)
注意Service的隱式啟動再5.0+上的問題,需要將隱式Intent轉為顯式
服務端Handler
public class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 1){
Log.e("MessengerHandler", msg.getData().getString("msg"));
Messenger client = msg.replyTo;
Message message = Message.obtain();
message.what = 1;
Bundle bundle = new Bundle();
bundle.putString("reply","shou dao le.");
message.setData(bundle);
try {
client.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
服務端Service
public class MessengerService extends Service {
Messenger messenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
<service android:name=".MessengerService" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="com.itszt.lww"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
客戶端Handler
public class ClientMHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 1){
String str = msg.getData().getString("reply");
if (BuildConfig.DEBUG) Log.e("ClientMHandler", str);
}
}
}
客戶端調起遠程服務
intent = new Intent("com.itszt.lww");
bindService(createExplicitFromImplicitIntent(this,intent),conn, Service.BIND_AUTO_CREATE);
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Messenger messenger = new Messenger(iBinder);
if(messenger == null) return;
Message message = Message.obtain();
message.what = 1;
Bundle bundle = new Bundle();
bundle.putString("msg","i am a client.");
message.setData(bundle);
message.replyTo = new Messenger(new ClientMHandler());
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
使用AIDL
在上述的AIDL初了解的基礎上,咱們來實現簡單的AIDL通信。增加一個Service提供給客戶端調起,并返回咱們定義IBookManager對應的IBinder對象
public class AIDLService extends Service {
// 保證高并發問題
List<Book> books = new CopyOnWriteArrayList<>();
RemoteCallbackList<IOnNewBookAddedListener> listeners = new RemoteCallbackList<>();
{
books.add(new Book(1,"java",66.3));
books.add(new Book(2,"php",61.3));
books.add(new Book(3,"c++",65.3));
}
IBookManager bookManager = new IBookManager.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
}
@Override
public List<Book> getBooks() throws RemoteException {
// 前面我們有提到AIDL只支持ArrayList
// 那么為什么我們這邊可以返回CopyOrWriteArrayList
// 是這樣的,服務器返回的CopyOrWriteArrayList會按List規范生成一個ArrayList傳給客戶端
// 類似的還有ConcurrentHashMap
return books;
}
@Override
public void addBookAndNotify(Book book) throws RemoteException {
addBook(book);
if(listeners == null) return;
int count = listeners.beginBroadcast();
for(int i = 0;i<count;i++){
IOnNewBookAddedListener listener = listeners.getBroadcastItem(i);
listener.onNewBook();
}
listeners.finishBroadcast();
}
@Override
public void registerListener(IOnNewBookAddedListener l) throws RemoteException {
if(listeners == null)
listeners = new RemoteCallbackList<>();
listeners.beginBroadcast();
listeners.register(l);
listeners.finishBroadcast();
if (BuildConfig.DEBUG) Log.e("AIDLServiceAdd", "listeners.size():" + listeners.beginBroadcast());
listeners.finishBroadcast();
}
@Override
public void unregisterListener(IOnNewBookAddedListener l) throws RemoteException {
if(listeners != null){
listeners.beginBroadcast();
listeners.unregister(l);
listeners.finishBroadcast();
}
if (BuildConfig.DEBUG) Log.e("AIDLServiceRemove", "listeners.size():" + listeners.beginBroadcast());
listeners.finishBroadcast();
}
};
@Override
public IBinder onBind(Intent intent) {
return bookManager.asBinder();
}
}
<service android:name=".AIDLService" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="com.itszt.aidl"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
客戶端調起服務獲得IBinder
public class MainActivity extends Activity {
IBookManager bookManager;
IOnNewBookAddedListener listener = new IOnNewBookAddedListener.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void onNewBook() throws RemoteException {
Toast.makeText(MainActivity.this, "收到新書通知啦!!", Toast.LENGTH_SHORT).show();
}
};
Intent intent;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if(iBinder == null) return;
bookManager = IBookManager.Stub.asInterface(iBinder);
if(bookManager == null) return;
try {
iBinder.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
unbindService(conn);
bindService(intent,conn,Service.BIND_AUTO_CREATE);
}
},0);
bookManager.registerListener(listener);
Toast.makeText(MainActivity.this, bookManager.getBooks().toString(), Toast.LENGTH_SHORT).show();
bookManager.addBook(new Book(5,"mXx",90));
bookManager.addBookAndNotify(new Book(5,"mXx",90));
// Toast.makeText(MainActivity.this, bookManager.getBooks().toString(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent("com.itszt.aidl");
bindService(createExplicitFromImplicitIntent(this,intent),conn, Service.BIND_AUTO_CREATE);
}
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
@Override
protected void onDestroy() {
if(bookManager!=null && bookManager.asBinder().isBinderAlive()){
try {
bookManager.unregisterListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
super.onDestroy();
}
}
AIDL中可以使用的數據類型
基本數據類型(int char double boolean long)
String和CharSequence
List:只支持ArrayList并且每個元素都被aidl支持
Map:只支持HashMap并且每個元素都被aidl支持
Parcelable:所有實現了Pacelable接口的對象
AIDL:所有aidl接口本身也可以在aidl中使用
注意:
1 在AIDL文件中必須顯式import所使用到的Parcelable子類以及aidl
2 所有用于AIDL的Parcelable類必須創建一個同名的aidl文件(聲明它為Parcelable類型)
3 除了基本數據類型外其他類型的方法參數都必須標識方向(in/out/inout)
不要圖方便全部使用inout,因為這在底層實現是有開銷的
Stub是服務器與Binder的中介
Proxy是客戶端與Binder的中介
多進程間是內存獨立的,進程1傳遞對象A給進程2,Binder會將對象A重新轉換生成一個新的對象。對象是不能跨進程直接傳輸的,對象的跨進程傳輸本質是序列化
RemoteCallbackLsit是系統專門提供用于管理跨進程Listener的,其內部封裝一個Map
6 ContentProvider
ContentProvider 同樣可以實現IPC,或者換個說法。ContentProvider 本質就是通過AIDL實現的。只不過它的職責專一,就是為其他應用提供數據的
Binder連接池
在前面說到AIDL的使用及原理的時候,我們可以看到在服務端只是創建了一個Binder然后返回給客戶端使用而已。于是我們可以想到是不是我們可以只有一個Service,對于不同可客戶端我們只是去返回一個不同的Binder即可,這樣就避免了創建了大量的Service。在任玉剛的《android開發藝術探索》給出了一個Binder連接池的概念,很巧妙的避免了Service的多次創建。這個Binder連接池類似于設計模式中的工廠方法模式。為每一個客戶端創建他們所需要的Binder對象。那么下面我們看一下它是如何實現的
首先我定義了多個AIDL,總的就是提供BookManager與StudentManager的功能。注意,這邊還有個IBinderPool,這個的功能是提供用戶選擇具體需要的IBinder對象
服務端 BinderPoolService 中返回了binderPool對象,客戶端可以通過該對象的queryBinder方法獲取對應的服務
public class BinderPoolService extends Service {
public class BookManagerImpl extends IBookManager.Stub{
List<Book> bs = new CopyOnWriteArrayList<>();
{
bs.add(new Book(1,"android",33));
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Book> getBooks() throws RemoteException {
return bs;
}
}
public class StudentManagerImpl extends IStudentManager.Stub{
List<Student> ss = new CopyOnWriteArrayList<>();
{
ss.add(new Student(1,"lee",19));
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public List<Student> getStudents() throws RemoteException {
return ss;
}
}
IBookManager bookManager = new BookManagerImpl();
IStudentManager studentManager = new StudentManagerImpl();
IBinderPool binderPool = new IBinderPool.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public IBinder queryBinder(int binderCode){
switch (binderCode){
case 1:
return bookManager.asBinder();
case 2:
return studentManager.asBinder();
}
return null;
}
};
@Override
public IBinder onBind(Intent intent) {
return binderPool.asBinder();
}
}
客戶端的定義了 BinderPool,相當于提供遠程服務調用工具類。這邊可以考慮使用CountDownLatch將遠程服務的連接這個異步操作轉為同步
public class BinderPool {
private Context context;
private CountDownLatch countDownLatch;
private static BinderPool binderPool;
private IBinderPool iBinderPool;
private BinderPool(Context context) {
this.context = context;
// 連接遠程線程池服務
connectBinderPoolService();
}
public static BinderPool getInstance(Context context) {
if (binderPool == null) {
synchronized (String.class) {
if (binderPool == null)
binderPool = new BinderPool(context);
}
}
return binderPool;
}
private synchronized void connectBinderPoolService() {
// countDownLatch = new CountDownLatch(1);
Intent intent = new Intent("com.itszt.lwwp");
context.bindService(ServiceIntentUtil.createExplicitFromImplicitIntent(context, intent),
conn, Service.BIND_AUTO_CREATE);
// try {
// // countDownLatch.await();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iBinderPool = IBinderPool.Stub.asInterface(iBinder);
// countDownLatch.countDown();
if (null != iBinderPool) {
try {
iBinderPool.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (iBinderPool != null) {
iBinderPool.asBinder().unlinkToDeath(this, 0);
iBinderPool = null;
// 重連
connectBinderPoolService();
}
}
};
public IBinder queryBinder(int binderCode) {
try {
if (iBinderPool != null)
return iBinderPool.queryBinder(binderCode);
return null;
} catch (RemoteException e) {
e.printStackTrace();
return null;
}
}
}
客戶端通過BinderPool調起遠程服務
new Thread(){
@Override
public void run() {
binderPool = BinderPool.getInstance(MainActivity.this);
}
}.start();
public void onTest(View view) {
if(binderPool == null) return;
IBookManager bookManager = IBookManager.Stub.asInterface(binderPool.queryBinder(1));
IStudentManager studentManager = IStudentManager.Stub.asInterface(binderPool.queryBinder(2));
try {
Toast.makeText(this, "bookManager.getBooks():" + bookManager.getBooks().toString(), Toast.LENGTH_SHORT).show();
Toast.makeText(this, "studentManager.getBooks():" + studentManager.getStudents().toString(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
總結
IPC是什么?是跨進程通信
AIDL是什么?是IPC方式的一種
IPC為什么會導致那么多問題?內存獨立
我們在什么時候需要IPC?某功能需要運行在獨立進行;提升應用分配內存;應用間交互