android IPC 机制

p, li { white-space: pre-wrap; }

IPC即Inter-Process Communication,含义为进程间的通信或者跨进程通信,是指两个进程之间进行数据交换的过程。

android 中使用多进程

android中使用多进程很“简单”,简单到只需要一行代码就可以开启一个进程。但是真正要用好多进程还是不简单的。android中使用进程只需要在manfiest中进行申明,形式如下:


当然,也可以process的属性也可以设为以":"开始,例如

android:process =":remote"

表示运行在当前activity或者service的包名+.remote

Binder基础

什么是binder?

Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,他的设备驱动是/dev/binder,该通信方式在Linux中没有。从Android Framework角度说,Binder是ManagerService的桥梁。从Android应用层角度来说,Binder是客户端和服务端调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。

使用基础

本例将用aidl实现进程间的通信,同时服务端将会每隔5s给订阅图书信息的人发一条信息,同时客户端也可以其进行订阅和取消订阅操作。
首先先给出使用实例的整体框架视图,如图:

android IPC 机制_第1张图片
11-00-49.jpg

首先新建一个序列化的bean对象,命名为Book.java。

public class Book implements Parcelable {

private int id;
private String bookName;

public Book(int id, String bookName) {
this.id = id;
this.bookName = bookName;
}

@Override
public String toString() {
return "Book{" +
"id=" + id +
", bookName='" + bookName + '\'' +
'}';
}

protected Book(Parcel in) {
id = in.readInt();
bookName = in.readString();
}

public static final Creator CREATOR = new Creator() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}

@Override
public Book[] newArray(int size) {
return new Book[size];
}
};

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(bookName);
}
}

然后新建aidl文件夹,并在里面添加Book.aidl文件,代码为:

// Book.aidl.aidl
package reoger.hut.test2;
parcelable Book;

记住一点,在aidl中,无论代码是否存在于同一个包中,都需要进行导入。
IBookManager.aidl的逻辑代码如下:

// IBookManager.aidl
package reoger.hut.test2;

import reoger.hut.test2.Book;
import reoger.hut.test2.IOnNewBookArrivedArrivedListener;

interface IBookManager {
List getBookList();
void addBook(in Book book);

void registerListener(IOnNewBookArrivedArrivedListener listener);
void unRegisterListener(IOnNewBookArrivedArrivedListener listener);
}

然后是IOnNewBookArrivedArrivedListener.aidl的代码,如下:

// IOnNewBookArrivedArrivedListener.aidl
package reoger.hut.test2;

import reoger.hut.test2.Book;

interface IOnNewBookArrivedArrivedListener {
void onNewBookArrived(in Book newBook);
}

接下来是我们服务端的实现,这里我采用的是通过一个service来实现,
BookManagerService.java的代码如下。

public class BookManagerService extends Service {

private CopyOnWriteArrayList mBookList = new CopyOnWriteArrayList();
private RemoteCallbackList mListeners = new RemoteCallbackList<>();

private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);

private Binder mBinder = new IBookManager.Stub() {

@Override
public List getBookList() throws RemoteException {
return mBookList;
}

@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}

/**
* 注册监听
* @param listener 监听对象
* @throws RemoteException
*/
@Override
public void registerListener(IOnNewBookArrivedArrivedListener listener) throws RemoteException {
mListeners.register(listener);
Log.d("TAG", "增添监听成功");
}

@Override
public void unRegisterListener(IOnNewBookArrivedArrivedListener listener) throws RemoteException {
mListeners.unregister(listener);
Log.d("TAG", "增添监听成功");
}
};

@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1, "android"));
mBookList.add(new Book(2, "ios"));

new Thread(new ServiceWorker()).start();

}

public BookManagerService() {
}

@Override
public IBinder onBind(Intent intent) {
int check = checkCallingOrSelfPermission("reoger.hut.test2.permission.ACCESS_BOOK_SERVICE");
if(check == PackageManager.PERMISSION_DENIED){
Log.e("TAG","没有对应的权限,无法启动service");
return null;
}
return mBinder;
}

private class ServiceWorker implements Runnable {

@Override
public void run() {
while (!mIsServiceDestoryed.get()) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}

int bookId = mBookList.size() + 1;
Book book = new Book(bookId, "new Book# " + bookId);
onNewBookArrived(book);
}
}
}

private void onNewBookArrived(Book book) {

mBookList.add(book);
final int N = mListeners.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedArrivedListener listener = mListeners.getBroadcastItem(i);
Log.d("TAG", "onNew Book Arrived ,notify listener :");
try {
if (listener != null) {
listener.onNewBookArrived(book);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
mListeners.finishBroadcast();
}
}

在manfiest文件中对service进行申明,并将其设置在一个单独的线程中运行,代码如下:



最后是我们的客户端代码,如下:

public class MainActivity extends AppCompatActivity {

private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {

switch (msg.what){
case 0x66:
Log.d("TAG","普天同庆 奔走相告"+msg.obj);
break;
default:
super.handleMessage(msg);
}
}
};

private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);

List list = null;
try {
list = bookManager.getBookList();
for (Book book : list) {
Log.d("TAG",book.toString());
}

Book book = new Book(3,"android 开发艺术探索");
bookManager.addBook(book);
List list2 = bookManager.getBookList();
for (Book book1 : list2) {
Log.d("TAG","--- "+book1.toString());
}

bookManager.registerListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}

}

@Override
public void onServiceDisconnected(ComponentName name) {

}
};
private IBookManager bookManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,BookManagerService.class);
bindService(intent,connection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onDestroy() {
if(bookManager != null && bookManager.asBinder().isBinderAlive()){
try {
Log.d("TAG","正在停止服务...");
bookManager.unRegisterListener(mOnNewBookArrivedListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(connection);
super.onDestroy();

}

private IOnNewBookArrivedArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedArrivedListener.Stub(){

@Override
public void onNewBookArrived(Book newBook) throws RemoteException {
mHandler.obtainMessage(0x66,newBook).sendToTarget();
}
};
}

最后运行的结果主要通过打印的日志来显示。

android IPC 机制_第2张图片
11-12-51.jpg

通过日志信息,可以明确看到我们的服务端和客服端的确进行的数据交换,并且服务端每隔5s发送一个信息给客户端。

关于AIDL,有以下的几点需要特别的注意:

  • AIDL支持基本的数据类型(除short以外的数据类型),也支持String和CharSequence和Parcelable。对于List只支持ArrayList,对于Map只支持HshMap.
  • 如果AIDL文件中用到了自定义的Parcelable对象,必须新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型。可以参考上面的示例 。
  • AIDL中除了基本的数据类型,其他类型的参数必须标上方向:in,out或者inout,in表示输入型参数,out表示输出型参数,inout表示输入输出型参数。
  • 在AIDL中,只支持方法,不支持声明静态常量。
  • AIDL包结构在服务端和客户端必须保持一致,否运行会出错,这是因为客户端需要反序列化服务端中和AIDL接口相关的所有类。
  • AIDL方法是执行在服务端的Binder线程池中的。

你可能感兴趣的:(android IPC 机制)