IPC是Inter-Process-Communication的简写,就是指进程间通讯。
Linux的进程间通讯,不必多说,就是指管道,信号和跟踪,信号量,套字节,共享内存等。
在这里主要讨论的是Android开发中常用的IPC方案。
目前为止,我们常用的IPC方案有以下几种:
1.使用Bundle
2.使用文件共享
3.使用Messenger(信使)
4.AIDL
5.ContentProvider组件
6.socket套字节
7.Binder线程池
现在让我一点一点总结,但是不会像前几篇打开源码一点点说,这是个总结:
1.Bundle 这是每一个每一个初学者都会接触到的一个类:
我们写Activity的onCreate():
protected void onCreate(Bundle savedInstanceState)
当时我初学的时候,查了一下文档,上面的说法大概是Bundle是作用存储Activity里面的信息。
正如上面创建Activity一样,四大组件中的三大组件都支持Intent中传递Bundle数据。Bundle实现了Parcelable接口,所以它可以很轻松在不同的进程之间传递。
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
前面也说过,Binder作为进程间的核心机制来说,就是使用序列化的Parcelable进行传递的。也是因此Bundle只支持基本类型,实现了Parcelable接口的类,或者说也实现了Serializable的数据类型,还有一些Android支持的特殊的对象啊。
有一个特殊场景需要注意一下:A进程要进行一个计算,并把计算完成后,这个结果要启动进程B的一个组件并把结果发给B进程的一个组件。可是这个结算结果不支持放入Bundle怎么办。
可以有一个解决方案:我们通过Intent启动B进程的Service,将数据传到B的Service进行计算,再让Service器启动B进程中真正要启动的目标组件。这样就避免了自己去做进程间通讯。
2.文件共享
这里面也包含了SharePreference的方案,其实就是我们学Java里面的用过的知识,BufferedRead和PrintWriter一起运用序列化写入一个约定的好文件,在通过反序列化读出来。要么就用Android封装好的SharePreference,去解析里面的内容。
3.使用信使也就是Messenger
Messenger是用AIDL实现的轻量化的IPC方案。
让我们粗略的看看下面的怎么样:
public final class Messenger implements Parcelable
首先,Messenger已经实现了序列化,为了进程间通讯做准备。
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public IBinder getBinder() {
return mTarget.asBinder();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
很熟悉吧,就是之前分析过AIDL,将所有的工作丢到IMessenger这个Binder类中工作,并且实现进程间通讯。
由于Messenger一次只做一个请求,因此,我们不需要考虑线程同步问题。那么Messenger实现步骤分两步:实现服务端和客户端:
1)实现服务端进程创建一个Service来处理来自客户端的请求,接着在Service的onBind返回的Binder进行处理。(为了证明能够完成进程通信,请在AndroidManifest.xml注册Service增加一个属性android:process=”:remote”)
MessengerService.java
public class MessengerService extends Service{
private static String Tag = "Messenger";
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg){
switch (msg.what) {
case 1:
Log.e(Tag, "receive msg from Client:" + msg.getData().getString("msg"));
Messenger client = msg.replyTo;//此处是当从客户端发送消息过来是后,声明的新Messenger
Message replyMessage = Message.obtain(null,0);
Bundle bundle = new Bundle();//Bundle作为数据传输的容器
bundle.putString("reply","received");
replyMessage.setData(bundle);
try {
client.send(replyMessage);//发送到客户端
} catch (RemoteException e) {
// TODO: handle exception
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
break;
}
}
}
private final Messenger messenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return messenger.getBinder();
}
MainActivity.java
public class MainActivity extends Activity {
private static final String TAG = "MessageActivity";
private Messenger mService;
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
}
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// TODO Auto-generated method stub
mService = new Messenger(service);//客户端发向服务端的数据
Message msg = Message.obtain(null,1);//1是message的what,标志位
Bundle data = new Bundle();
data.putString("msg", "hello,this is client");
msg.setData(data);
msg.replyTo = mGetReplyMessenger;//对返回的Msg处理
try{
mService.send(msg);//客户端发送到服务端的数据
}catch(RemoteException e){
e.printStackTrace();
}
}
};
//此处是处理从服务器返回的数据
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg){
Log.e("handler", "handle");
switch (msg.what) {
case 0:
Log.e(TAG, "0");
Log.e(TAG, "receive msg from Service:" + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
break;
}
}
}
@Override
protected void onDestroy(){
unbindService(mConnection);
super.onDestroy();
}
}
这里要注意,发送端发到接收端,那么接收端就必须有一个Handler来处理。一般的以客户端发向服务端的方向作为基准,要接受数据,客户端要有replyTo应答:msg.replyTo = Handler。服务端则是需要通过msg.replyTo来声明一个新的Messenger。
这样就能够完成进程间通讯。
以后空在慢慢研究Meesenger,整理出文章,现在只需要怎么用就行。
4.AIDL的使用:
AIDL的使用在前面说了一下,现在介绍怎么使用。
第一步:我们需要建立一个包,里面放的全是AIDL的文件以及AIDL相关的类。为什么这么做呢?这是因为我们要这个AIDL的文件放入客户端里面,来办到进程间通讯。如果不这么做,反序列和序列化的时候,Parcelable是根据包的结构做出像Serializable那样的序列码,如果包的结构不一样,序列会出现问题。
第二步:在这个包里面,创建aidl文件,在里面不是.java格式,因此我们只能手动的声明package,import类进来。注意在这里面,这能够处理基本数据类型,实现了Parcelable接口的类。
支持类型如下:
基本类型:int,long,char,boolean,double等
String,CharSequence;
List:支持ArrayList
Map:只支持HashMap
Parcelable:支持所有实现了Parcelable的接口
AIDL:AIDL本省也可以调用AIDL
这里我们做一个远程服务通知有新书的到来的一个过程
如下:
Book.aidl
package com.example.bindertest.aidl;
parcelable Book;
IBookManager.aidl
package com.example.bindertest.aidl;
import com.example.bindertest.aidl.Book;
import com.example.bindertest.aidl.IOnNewBookArrived;
interface IBookManager{
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrived listener);
void unregisterListener(IOnNewBookArrived listener);
}
IOnNewBookArrived.aidl
package com.example.bindertest.aidl;
import com.example.bindertest.aidl.Book;
import com.example.bindertest.aidl.IOnNewBookArrived;
interface IBookManager{
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrived listener);
void unregisterListener(IOnNewBookArrived listener);
}
我们要做的目的,就是为了实现进程两端的相互的通信,因此,在Service端实现了功能为:返回书本的list,添加书本,绑定观察者,解绑观察者的Binder,将参数发送到另一端处理。
而在Activity中实现了一旦新书到达就发送的通知Binder,由于我们需要一个Handler来处理消息,因此这个Binder声明在客户端。此时在这个Binder中,那么相对于Service组件来说,Activity组件此时作为服务端,Service组件作为客户端。这个思想我发现在我研究四大组件的时候经常使用。
说明就这么多,下面是源码:
BookManager.java
public class BookManagerService extends Service{
private static final String TAG = "BMS";
/*作为线程同步时候的容器,线程写入的时候不会写入内存,而是写入副本**/
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
/*判断Service是否存活的原子类**/
private AtomicBoolean mIsServiceDestroyed = new AtomicBoolean(false);
/*IInterface的callback对象存入了真正的Binder对象,不然移除对象的时候,移除不干净**/
private RemoteCallbackList<IOnNewBookArrived> mListenerList = new RemoteCallbackList<IOnNewBookArrived>();
//调用AIDL中Stub抽象类,在Service中实现本地方法
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
// TODO Auto-generated method stub
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
// TODO Auto-generated method stub
mBookList.add(book);
}
@Override
public void registerListener(IOnNewBookArrived listener)
throws RemoteException {
// TODO Auto-generated method stub
mListenerList.register(listener);
}
@Override
public void unregisterListener(IOnNewBookArrived listener)
throws RemoteException {
// TODO Auto-generated method stub
mListenerList.unregister(listener);
}
};
/*为了让我们的远程服务不让任何客户端连上,我们做一个permission权限的检查**/
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
int check = checkCallingOrSelfPermission("com.example.bindertest.permission.ACCESS_BOOK_SERVICE");
if(check == PackageManager.PERMISSION_DENIED){
return null;
}
return mBinder;
}
@Override
public void onCreate(){
super.onCreate();
mBookList.add(new Book(1, "Android"));
mBookList.add(new Book(2, "IOS"));
new Thread(new ServiceWorker()).start();
}
@Override
public void onDestroy(){
mIsServiceDestroyed.set(true);
super.onDestroy();
}
/*在这里我们从存了Binder的list中取出实例,这个list相当于观察者模式这通知后,被观察者做出相应的动作**/
private void onNewBookArrived(Book book)throws RemoteException{
mBookList.add(book);
final int N = mListenerList.beginBroadcast();
for(int i=0;i<N;i++){
IOnNewBookArrived l = mListenerList.getBroadcastItem(i);
if(l != null){
try{
/*这里调用调用另一端Notify通知方法**/
l.onNewBookArrived(book);
}catch (RemoteException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
mListenerList.finishBroadcast();
}
/*启用线程,为的是每5秒模拟发送一个通知的情景**/
private class ServiceWorker implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
while(!mIsServiceDestroyed.get()){
try {
Thread.sleep(5000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
int bookid = mBookList.size()+1;
Book newBook = new Book(bookid, "new book#"+bookid);
try {
onNewBookArrived(newBook);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
}
下面是MainActitivty.java
public class MainActivity extends Activity {
private static final String TAG = "BookManagerActvity";
private static final int MESSAGE_NEW_BOOK_ARRIVED = 1;
private IBookManager mRemoteBookManager;
//这里是处理器,为了处理从服务端发过来的信息
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg){
switch (msg.what) {
case MESSAGE_NEW_BOOK_ARRIVED:
Log.e(TAG, "received a new book"+msg.obj);
break;
default:
super.handleMessage(msg);
break;
}
}
};
//声明ServiceConnect用于绑定服务
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName classname) {
// TODO Auto-generated method stub
}
@Override
public void onServiceConnected(ComponentName classname, IBinder service) {
// TODO Auto-generated method stub
//判断是本地还是远程的
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try{
List<Book> list = bookManager.getBookList();
Log.e(TAG, "query listType:"+list.getClass().getCanonicalName());
Log.e(TAG, "query list element:"+list.toString());
Book newbook = new Book(323, "a new book");
bookManager.addBook(newbook);
List<Book> list2 = bookManager.getBookList();
Log.e(TAG, "query list2 element:"+list2.toString());
mRemoteBookManager = bookManager;
Book book2 = new Book(3, "Android up");
mRemoteBookManager.addBook(book2);
List<Book> list3=mRemoteBookManager.getBookList();
Log.e(TAG, "query list2 element:"+list3.toString());
bookManager.registerListener(listener);//绑定观察者监听器
}catch(RemoteException e){
e.printStackTrace();
}
}
};
/*在这里实现了加入观察者出现了变化,则发送一个Msg到Handler**/
private IOnNewBookArrived listener = new IOnNewBookArrived.Stub() {
@Override
public void onNewBookArrived(Book book) throws RemoteException {
// TODO Auto-generated method stub
mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED,book).sendToTarget();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MainActivity.this,BookManagerService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy(){
if((mRemoteBookManager != null)&&mRemoteBookManager.asBinder().isBinderAlive()){
try {
Log.e(TAG, "unregister listener:"+listener);
mRemoteBookManager.unregisterListener(listener);//解除监听器的绑定
} catch (RemoteException e) {
// TODO: handle exception
e.printStackTrace();
}
}
unbindService(conn);
super.onDestroy();
}
}
5.内容提供器
因为Sqlite不允许多进程的访问,ContentProvider做出了允许同步的方案。
具体一般人都会,这就略。
6.socket套字节
本地是通过端口来访问,单独开下一章来总结
7.Binder连接池
Binder连接池,其实就是使用aidl。为什么分开来说呢,主要是因为在需求中有可能会出现需要控制多个aidl,难道我们一个个去实现每一个函数,这明显不可能,我需要的是BinderPool这种策略。
单独开一章来总结。