一,什么是IPC

IPC:inter-process communication,进程间通信或者跨进程通信。window通过剪贴板,管道等进行进程间通信。Linux通过命名管道,共享内存,信号量等进行进程间通信。android有特色的是Binder。 在android进程通信可以有以下方式:aidl,socket通信,使用Bundle,使用contentprovider,使用Messenger,使用文件共享。

二,android的序列化

在android中能用于进程间通信的对象必须是序列化的。序列的方式有两种,一种是实现Serializable接口,一种是实现Parcelable。Serializable是java提供的序列化方法,实现很简单,只要一个类实现了它就完成了序列化。可用于将对象序列化到存储设备或序列化后通过网络传输。但它的效率不高,这里重点介绍Parcelable,它是android自己的实现序列化方法,先看实现Parcelable的代码:
只要一个类实现了这个接口,就可以实现序列化并可以通过Intent和Binder传递。要实现以下方法 (1).writeToParcel(out,flags):实现序列化功能,一系列write。如下 out.writeInt(userId); out.writeParcelable(book,0);//传另一个序列化类 (2).CREATOR:反序列化,一系列的read方法:如下 userId = in.readInt(); book = in.readParcelable(Thread.currentThread().getContextClassLoader()); (3).decribeContents:内容描述,几乎所有情况都返回0. 完整代码如下
public class Book implements Parcelable {    public int bookId;    public String bookName;    public Book() {    }    public Book(int bookId, String bookName) {        this.bookId = bookId;        this.bookName = bookName;    }    public int describeContents() {        return 0;    }    public void writeToParcel(Parcel out, int flags) {        out.writeInt( bookId);        out.writeString( bookName);    }    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {        public Book createFromParcel (Parcel in) {            return new Book(in);        }        public Book[] newArray( int size) {            return new Book[size];        }    };    private Book(Parcel in) {        bookId = in.readInt();        bookName = in.readString();    }    @Override    public String toString() {        return String.format("[bookId:%s, bookName:%s]" , bookId , bookName);    }}


系统还提供了一些实现了Parcelable接口的类,如Intent,Bundle,Bitmap.同时List和Map也可以序列化,前提是它们里所有元素都 可以序列化。 Parcelable效率比Serializable高,在内存序列化上用它合适。但在将对象序列化到存储设备或序列化后通过网络传输则建议用Serializable,比较方便。

二,Binder的介绍

Binder用于完成进程间的通信(IPC)。Binder是工作在Linux层,属于一个驱动,这个驱动不需要驱动,Binder代码运行在内核态,调用Binder是系统进行调用。
Binder是一种架构,这种架构提供服务端接口,Binder接口,客户端接口三个模块。一个Binder服务端就是一个Binder对象,该对象一旦创建,就会启动一个隐藏线程,该线程会接Binder驱动发送的消息。收到消息会发调用 onTransact()方法,并按照参数执行不同的服务代码,onTransact()的参数来源是客户端调用 transact(),若transact()有固定的输入,onTransact()就有固定的输出 。 一个服务端被创建,会创建一个mRemote对象,它的类型也是Binder类,客户端要访问远程时是通过它。它也重载了transact()方法,重载内容如下: 1,以线程消息通信模式,向服务端发送客户端传递过来的参数。 2.挂起当前线程,并等待服务端线程执行完指定服务函数后通知。 3.接收服务端通知并执行客户端线程,并返回到客户端代码区。 它的调用图如下:
接下来我们来看看如何使用它。 新建两个文件Book.aidl,IBookManager.aidl,其中Book.aidl是上面序列化后文件的一个声明,主意名称要和序列化的类的名称一样。内容如下:
package com.lxj.aidl;parcelable Book;
再看下 IBookManager.aidl,这个demo主要实现两个方法,所以都需要这此声明:
package com.lxj.aidl;import com.lxj.aidl.Book;interface IBookManager {     List<Book> getBookList();     void addBook(in Book book);}
除了基本数据类型外,其它数据类型都要以in out inout来标识,in表示输入,out表示输出,inout即可表示输入也可表示输出。
这时系统会自动生成一个 IBookManager.java文件,内容如下:
package com.lxj.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.lxj.aidl.IBookManager{private static final java.lang.String DESCRIPTOR = "com.lxj.aidl.IBookManager";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.lxj.aidl.IBookManager interface, * generating a proxy if needed. */public static com.lxj.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.lxj.aidl.IBookManager))) {return ((com.lxj.aidl.IBookManager)iin);}return new com.lxj.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.lxj.aidl.Book> _result = this.getBookList();reply.writeNoException();reply.writeTypedList(_result);return true;}case TRANSACTION_addBook:{data.enforceInterface(DESCRIPTOR);com.lxj.aidl.Book _arg0;if ((0!=data.readInt())) {_arg0 = com.lxj.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.lxj.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.lxj.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.lxj.aidl.Book> _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);_reply.readException();_result = _reply.createTypedArrayList(com.lxj.aidl.Book.CREATOR);}finally {_reply.recycle();_data.recycle();}return _result;}@Override public void addBook(com.lxj.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.lxj.aidl.Book> getBookList() throws android.os.RemoteException;public void addBook(com.lxj.aidl.Book book) throws android.os.RemoteException;}
asInterface:用于将服务端的Binder对象转换成客户端所需的AIDL对象,同一进程返回的是服务端的Stub,不同进程返回系统封闭后的Stub.proxy对象。 asBinder:用于返回当前 的Binder对象。 onTransact(code,data,reply,flags):运行在服务端的Binder线程池中,客户端发出的请求会在此处理。code可以确定客户端的请求目标方法是什么,data取出参数,运行完把结果赋给reply。如果返回false,则客户端请求会失败(可用于权限判断)。 getBookList:首先创建输入输出的Parcel对象_data,_reply。接着调用transact方法来发起RPC(远程过程调用)请求,同时挂起线程,然后服务端onTransact会调用,直到RPC执行完,当前线程继续执行,并从_reply取出RPC结果。返回。

四,AIDL进程间调用

aidl是最常见的进程调用方式。我们先创建两个应用,模拟进程间通信(不同应用)。客户端的代码如下:
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent("com.lxj.servicetest.MyAIDLService");        bindService(intent, connection, Context.BIND_AUTO_CREATE);}private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubIBookManager bookManager = IBookManager.Stub.asInterface(service);try {List<Book> list = bookManager.getBookList();Log.e("list", list.toString());} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}};
通过bindService绑定服务端Binder,然后通过IBookManager.Stub.asInterface()来获得服务端返回的AIDL对象,就可以调用到服务端的方法(getBookList)。再看下服务端代码:
public class MyBookService extends Service {private CopyOnWriteArrayList<Book> mBooks = new CopyOnWriteArrayList<Book>();@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();mBooks.add(new Book(1,"java虚拟机"));mBooks.add(new Book(2,"android疯狂讲义"));}private Binder mBinder = new IBookManager.Stub() {//虽然IBinder只能传输List,但是服务端之所以可以用CopyOnWriteArrayList是因为它会自动在传输时转化为list@Overridepublic List<Book> getBookList() throws RemoteException {// TODO Auto-generated method stubreturn mBooks;}@Overridepublic void addBook(Book book) throws RemoteException {// TODO Auto-generated method stubmBooks.add(book);}};@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn mBinder;}}
自定义了一个Service并在list中添加两本书,所以客户端就能在控制台上打印出这两本书。注意要在AndroidFest.xml添加上Service的声明:
   <service            android:name="com.lxj.aidl.MyBookService"            >            <intent-filter>              <action android:name="com.lxj.servicetest.MyAIDLService"/>          </intent-filter>         </service>

四,Messenger进程间通信

android提供Messenger可以实现不同进程间的信息传递,相比AIDL它的调用简单很多,但是它是有缺点的,它只能串行处理发送的信息,如里信息过多就会阻塞。其次它只能传输基本数据类型,What,arg1,Bundle等,并不能传输自定义的对象。Messenger是一种种轻量级的IPC方案,一次处理一个请求。 1.服务端: 创建一个Service来处理客户端连接请求,同时创建一个Handler并通过它来创建一个Message对象,然后在OnBinder中返回这个Binder。 2.客户端: 首先绑定服务端Service,通过返回的IBinder创建一个messager。这个就可以给服务端发消息了,如果需要服务端返回,则也要跟服务端一个创建Handler,通过Message的replyTo参数传递给服务端。 先看下客户端的代码: 先看客户端代码:
public class MainActivity extends Activity {TextView txvTextView ;private Messenger mService;private Messenger clientMessenger = new Messenger(new MessengerHandler());private static class MessengerHandler extends Handler{@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch(msg.what){case 1:Log.e("msg from service",  msg.getData().getString("reply"));break; default:        super.handleMessage(msg);}}}private ServiceConnection connection = new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stub mService = new Messenger(service);Message msgMessage = Message.obtain(null,0);Bundle b = new Bundle();b.putString("client", "Hi,i am client");msgMessage.setData(b);msgMessage.replyTo = clientMessenger;try {mService.send(msgMessage);} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stub}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);txvTextView = (TextView)super.findViewById(R.id.txv);Intent i = new Intent(this,MessengerService.class);bindService(i, connection, Context.BIND_AUTO_CREATE);}   @Override    protected void onDestroy() {        unbindService(connection);        super.onDestroy();    }}
看到上面的代码我们可以很清楚的看到,Messenger也是用AIDL实现进程间通信的。通过Messenger发送消息到服务端,handler中获取服务端返回的replyto。再看下服务端代码:
public class MessengerService extends Service{private final Messenger mMessenger = new Messenger(new MessengerHandler());private static class MessengerHandler extends Handler{@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch(msg.what){case 0:Log.e("msg from client",  msg.getData().getString("client"));Message message = Message.obtain(null,1);Messenger messenger = msg.replyTo;//从客户端得到的messenger,用于在客户端中显示Bundle bundle = new Bundle();bundle.putString("reply", "Hi,i am service");message.setData(bundle);try {Thread.sleep(1000);messenger.send(message);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}break; default:        super.handleMessage(msg);}}}@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn  mMessenger.getBinder();}}
这里就是获取到信息后再把信息发送回客户端。完成了不同进程的信息传递。 这里只是简单介绍两种IPC方式,还有很多常用方式如socket通信,ContentProvider等都可以实现IPC。本文只是总结下自己对IPC的认识。





更多相关文章

  1. Android手机客户端与Servlet交换数据(by quqi99)
  2. Android客户端与服务端通信乱码问题的解决
  3. Android(安卓)关机、重启、recovery流程分析
  4. Gridview制作表格
  5. Android中检测手机制式和移动网络类型
  6. 利用半透明对话框实现新浪微博android客户端首次运行时的提示界
  7. Android中service之初见
  8. Android中滑屏初探 ---- scrollTo 以及 scrollBy方法使用说明
  9. Android的三种网络通信方式

随机推荐

  1. Android自动化测试之MonkeyRunner之Monke
  2. 在 Android(安卓)Emulator 中开发 LKM 程
  3. Android(安卓)返回键退出
  4. Clickable URLs in Android(安卓)TextVie
  5. Android(安卓)HTTP请求
  6. android imageVIew拖动 && 图片缩放
  7. android 广播 android Service 开机启动
  8. Android(安卓)Accessibility(辅助功能) 学
  9. AndroidManifest.xml - 【 manifest -> A
  10. android秒表计时代码