在Android开发中IPC(Inter-Process Communication的缩写)多进程通信的使用场景很多。一般地由于某些功能模块需要特殊原因运行在单独的进程中,又或者为了加大一个应用可使用的内存,因为Android对单个应用使用的最大内存是有限制的,又或者需要做一些非常耗内存而又不好回收的事情,在事情完成后直接结束掉进程,等。开启多进程模式很简单,就是给四大组件指定android:process属性即可。IPC的方式有多种,在日常开发中涉及进程间通信时的首选应该就是AIDL了。我们就来以示例的方式学习AIDL的使用。
第一步,新建一个People的类,使它继承Parcelable,代码如下:
package com.zyx.aidldemo;
import android.os.Parcel;
import android.os.Parcelable;
public class People implements Parcelable {
public int pId;
public String pName;
public People() {
}
public People(int pId, String pName) {
this.pId = pId;
this.pName = pName;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(pId);
dest.writeString(pName);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public People createFromParcel(Parcel in) {
return new People(in);
}
public People[] newArray(int size) {
return new People[size];
}
};
private People(Parcel in) {
pId = in.readInt();
pName = in.readString();
}
@Override
public String toString() {
return String.format("pId:%s, pName:%s", pId, pName);
}
}
说明:
这里就不进行Parcelable详细的介绍了,大家在使用方面按照上例来一般都不会有问题。
第二步,创建AIDL接口文件People.aidl
package com.zyx.aidldemo;
parcelable People;
说明:
第三步,创建AIDL接口文件IPeopleManager.aidl
package com.zyx.aidldemo;
import com.zyx.aidldemo.People;
interface IPeopleManager {
List getPeopleList();
void addPeople(in People people);
}
IPeopleManager.adil中定义了一个接口,它的功能很简单就是获取列表对象和添加对象
注意:
第四步,此时,准备功能已经完成了,先对工程进行初始的编译,因为只要在编译后才可以将aidl文件转化成IPeopleManager.java文件:build\generated\source\aidl\debug\com\zyx\aidldemo\IPeopleManager.java
第五步,新建一个服务PeopleManagerService.java,并在AndroidManifest.xml中特意指定它在不同的进程android:process=":remote"代码如:
package com.zyx.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class PeopleManagerService extends Service {
// 是ArrayList 的一个线程安全的变体
private CopyOnWriteArrayList mPeopleList = new CopyOnWriteArrayList();
private Binder mBinder = new IPeopleManager.Stub() {
@Override
public List getPeopleList() throws RemoteException {
return mPeopleList;
}
@Override
public void addPeople(People people) throws RemoteException {
mPeopleList.add(people);
}
};
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
说明:
第六步,在MainActivity中绑定PeopleManagerService服务,并在绑定回调中进行跨进程添加对象和获得列表对象:
package com.zyx.aidldemo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
IPeopleManager peopleManager = IPeopleManager.Stub.asInterface(service);
try {
People people = new People(1, "子云心");
// 添加对象
peopleManager.addPeople(people);
// 获取对象列表
List list = peopleManager.getPeopleList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, PeopleManagerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
就这样,一次完整的使用AIDL进行IPC实例就完成。
在实际开发中远不止上例如此简单,假如现在需要在客户端增加一个监听,好让每次列表更新后就会进行一次通知,也就是一个典型的观察者模式。所以就有了以下的扩展。
第一步,因为AIDL中无法使用普通接口,所以得创建IOnNewPeopleListener.aidl文件:
package com.zyx.aidldemo;
import com.zyx.aidldemo.People;
interface IOnNewPeopleListener {
void onNewPeople(in People newPeople);
}
第二步,修改IPeopleManager.adil,加两个接口:
package com.zyx.aidldemo;
import com.zyx.aidldemo.People;
import com.zyx.aidldemo.IOnNewPeopleListener;
interface IPeopleManager {
List getPeopleList();
void addPeople(in People people);
// 扩展新增代码:新增接口
void registerListener(IOnNewPeopleListener listener);
void unregisterListener(IOnNewPeopleListener listener);
}
第三步,在执行编译后生成新的IPeopleManager.java后,进行PeopleManagerService的修改:
package com.zyx.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class PeopleManagerService extends Service {
// 是ArrayList 的一个线程安全的变体
private CopyOnWriteArrayList mPeopleList = new CopyOnWriteArrayList();
// 扩展新增代码:用于存储回调监听的接口列表
private CopyOnWriteArrayList mListenerList = new CopyOnWriteArrayList();
private Binder mBinder = new IPeopleManager.Stub() {
@Override
public List getPeopleList() throws RemoteException {
return mPeopleList;
}
@Override
public void addPeople(People people) throws RemoteException {
mPeopleList.add(people);
// 扩展新增代码:新加对象后执行监听回调
for (int i = 0; i < mListenerList.size(); i++) {
IOnNewPeopleListener listener = mListenerList.get(i);
listener.onNewPeople(people);
}
}
// 扩展新增代码:添加监听接口到列表
@Override
public void registerListener(IOnNewPeopleListener listener) throws RemoteException {
if (!mListenerList.contains(listener)) {
mListenerList.add(listener);
}
}
// 扩展新增代码:移除监听列表中的监听接口
@Override
public void unregisterListener(IOnNewPeopleListener listener) throws RemoteException {
if (mListenerList.contains(listener)) {
mListenerList.remove(listener);
}
}
};
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
最后一步,就是修改客户端MainActivity.java文件,客户端要注册IOnNewPeopleListener:
package com.zyx.aidldemo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.List;
public class MainActivity extends AppCompatActivity {
IPeopleManager mPeopleManager;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mPeopleManager = IPeopleManager.Stub.asInterface(service);
try {
// 扩展新增代码:注册监听
mPeopleManager.registerListener(mIOnNewPeopleListener);
People people = new People(1, "子云心");
mPeopleManager.addPeople(people);
List list = mPeopleManager.getPeopleList();
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
mPeopleManager = null;
}
};
// 扩展新增代码:定义监听接口
private IOnNewPeopleListener mIOnNewPeopleListener = new IOnNewPeopleListener.Stub() {
@Override
public void onNewPeople(People newPeople) throws RemoteException {
// TODO 这里子线程,如若需要修改UI请使用 Handler
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, PeopleManagerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
// 扩展新增代码:移除监听
if (mPeopleManager != null && mPeopleManager.asBinder().isBinderAlive()) {
try {
mPeopleManager.unregisterListener(mIOnNewPeopleListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mConnection);
super.onDestroy();
}
}
从扩展1中,其实存在一个bug,因为客户端MainActivity的移除监听根本就没有成功。why?因为客户端注册和移除注册过程中使用的虽是同一个客户端对象,但通过Binder传递到服务端后,产生了两个不同的对象,因为对象是不能跨进程直接传输的,对象的跨进程传输本质上都是反序列化的过程。所以就有了扩展2的修改:
第一步,修改服务端PeopleManagerService.java的几个方法代码:
// 扩展新增代码:用于存储回调监听的接口列表
// private CopyOnWriteArrayList mListenerList = new CopyOnWriteArrayList();
// 新扩展修改代码:将 CopyOnWriteArrayList 替换掉变成 RemoteCallbackList
private RemoteCallbackList mListenerList = new RemoteCallbackList();
@Override
public void addPeople(People people) throws RemoteException {
mPeopleList.add(people);
// 扩展新增代码:新加对象后执行监听回调
// for (int i = 0; i < mListenerList.size(); i++) {
// IOnNewPeopleListener listener = mListenerList.get(i);
// listener.onNewPeople(people);
// }
// 新扩展修改代码
final int N = mListenerList.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewPeopleListener listener = mListenerList.getBroadcastItem(i);
if (listener != null) {
try {
listener.onNewPeople(people);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
mListenerList.finishBroadcast();
}
// 扩展新增代码:添加监听接口到列表
@Override
public void registerListener(IOnNewPeopleListener listener) throws RemoteException {
// if (!mListenerList.contains(listener)) {
// mListenerList.add(listener);
// }
// 新扩展修改代码
boolean success = mListenerList.register(listener);
final int N = mListenerList.beginBroadcast();
mListenerList.finishBroadcast();
}
// 扩展新增代码:移除监听列表中的监听接口
@Override
public void unregisterListener(IOnNewPeopleListener listener) throws RemoteException {
// if (mListenerList.contains(listener)) {
// mListenerList.remove(listener);
// }
// 新扩展修改代码
boolean success = mListenerList.unregister(listener);
final int N = mListenerList.beginBroadcast();
mListenerList.finishBroadcast();
}
说明:
点击下载示例源码
——本文部分内容参考自《Android开发艺术探索》