概述 IPC(IPC,InterProcess Communication):在Android系统中一个应用至少有一个进程,每个进程都有自己独立的资源和内存空间,其它进程不能任意访问当前进程的内存和资源。如果进程之间想要进行通信,则需要使用IPC手段。
每个Android的进程,只能运行在自己进程所拥有的虚拟地址空间。对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。Client进程向Server进程通信,恰恰是利用进程间可共享的内核内存空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互。
Parcelable Android中实现序列化有两个选择:一是实现Serializable接口(是JavaSE本身就支持的),一是实现Parcelable接口(是Android特有功能,效率比实现Serializable接口高效,可用于Intent数据传递,也可以用于进程间通信(IPC))。实现Serializable接口非常简单,声明一下就可以了,而实现Parcelable接口稍微复杂一些,但效率更高,推荐用这种方法提高性能。
Android中Intent传递对象有两种方法:一是Bundle.putSerializable(Key,Object),另一种是Bundle.putParcelable(Key,Object)。当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口。
在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
步骤:
implements Parcelable
重写writeToParcel方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从 Parcel容器获取数据
重写describeContents方法,内容接口描述,默认返回0就可以
实例化静态内部对象CREATOR实现接口Parcelable.Creator
1 public static final Parcelable.Creator<T> CREATOR
注:其中public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。需重写本接口中的两个方法:createFromParcel(Parcel in) 实现从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层,newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话即可(return new T[size]),供外部类反序列化本类数组使用。
简而言之:通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象。也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,在通过createFromParcel从流里读取对象,只不过这个过程需要你来实现,因此写的顺序和读的顺序必须一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public class Person implements Serializable { private static final long serialVersionUID = -7060210544600464481L ; private String name; private int age; public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } } public class Book implements Parcelable { private String bookName; private String author; private int publishDate; public Book () { } public String getBookName () { return bookName; } public void setBookName (String bookName) { this .bookName = bookName; } public String getAuthor () { return author; } public void setAuthor (String author) { this .author = author; } public int getPublishDate () { return publishDate; } public void setPublishDate (int publishDate) { this .publishDate = publishDate; } @Override public int describeContents () { return 0 ; } @Override public void writeToParcel (Parcel out, int flags) { out.writeString(bookName); out.writeString(author); out.writeInt(publishDate); } public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>() { @Override public Book[] newArray(int size) { return new Book[size]; } @Override public Book createFromParcel (Parcel in) { return new Book(in); } }; public Book (Parcel in) { bookName = in.readString(); author = in.readString(); publishDate = in.readInt(); } }
Bundle Bundle 实现了 parcelable 接口。基于这一点,当启动另一个进程时,可使用 Bundle 传输能够被序列化的数据。如 Activity,BroadcastReceiver。
文件共享 文件共享适合在对数据同步要求不高的进程间进行通信。从本质上说,SharedPreference 也是文件,但由于系统对它的读写有一定的缓存策略,因此不建议在多进程间使用 SharedPreference。
ContentProvider BroadcastReceiver Socket Binder 见Android-Binder实战 。
Messenger 概述 Messenger 是一种轻量级的 IPC 方案,它的底层实现是 AIDL。 因为它对 AIDL 做了封装,所以使用起来非常简单,就类似于我们绑定一个 Service 一样。同时,由于它一次处理一个请求,所以在服务端我们不用考虑线程同步的问题,因为在服务端中不存在并发执行的情况。Messenger 和 Message 都实现了 Parcelable 接口,因此可以跨进程传输。简单来说, Message 中所支持的数据类型就是 Messenger 所支持的传输类型。
Messenger 比较适用于低并发的一对多的通信。
构造函数:
1 2 3 4 5 6 7 8 9 private final IMessenger mTarget;public Messenger (Handler target) { mTarget = target.getIMessenger(); } public Messenger (IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
服务端进程:
创建一个 Service 来处理客户端的连接请求;
创建一个 Handler 并通过它来创建一个 Messenger 对象;
在 Service 的 onBind 函数中返回这个 Messenger 对象底层的 Binder ;
客户端进程:
绑定服务端的Service;
绑定成功后用服务端返回的 IBinder 对象创建一个 Messenger;
通过这个 Messenger 向服务端发送消息,消息类型为 Message 对象;
创建一个 Handler 并创建一个新的 Messenger 对象;
将这个新的 Messenger 对象通过 Message 的 replyTo 参数传递给服务端,服务端就可以通过这个 replyTo 参数回应客户端了;
实例 客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class MainActivity extends AppCompatActivity { private Messenger messenger; private static class MessengerHandler extends Handler { @Override public void handleMessage (Message msg) { switch (msg.what) { case 1 : Log.i("LLL" , "client received: " + msg.getData().getString("reply" )); break ; } } } private Messenger replyMessenger = new Messenger(new MessengerHandler()); private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected (ComponentName componentName, IBinder iBinder) { Messenger messenger = new Messenger(iBinder); Message message = Message.obtain(); message.what = 0 ; Bundle bundle = new Bundle(); bundle.putString("client" , "this is message from client." ); message.setData(bundle); message.replyTo = replyMessenger; try { messenger.send(message); } 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 intent = new Intent(this , MessengerService.class); bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy () { super .onDestroy(); unbindService(serviceConnection); } }
服务端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class MessengerService extends Service { private static class MessengerHandle extends Handler { @Override public void handleMessage (Message msg) { switch (msg.what) { case 0 : Log.i("LLL" , "server received: " + msg.getData().getString("client" )); Messenger replyMessenger = msg.replyTo; Message replyMessage = Message.obtain(); Bundle bundle = new Bundle(); bundle.putString("reply" , "serve has received msg." ); replyMessage.what = 1 ; replyMessage.setData(bundle); try { replyMessenger.send(replyMessage); } catch (RemoteException e) { e.printStackTrace(); } break ; } } } private Messenger messenger = new Messenger(new MessengerHandle()); @Nullable @Override public IBinder onBind (Intent intent) { return messenger.getBinder(); } }
Service注册:
1 2 <service android:name =".MessengerService" android:process =":remote" />
源码 IMessenger.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 public interface IMessenger extends android .os .IInterface { public static abstract class Stub extends android .os .Binder implements android .os .IMessenger { private static final java.lang.String DESCRIPTOR = "android.os.IMessenger" ; public Stub () { this .attachInterface(this , DESCRIPTOR); } public static android.os.IMessenger asInterface (android.os.IBinder obj) { if ((obj == null )) { return null ; } android.os.IInterface iin = (android.os.IInterface) obj .queryLocalInterface(DESCRIPTOR); if (((iin != null ) && (iin instanceof android.os.IMessenger))) { return ((android.os.IMessenger) iin); } return new android.os.IMessenger.Stub.Proxy(obj); } 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_send: { data.enforceInterface(DESCRIPTOR); android.os.Message _arg0; if ((0 != data.readInt())) { _arg0 = android.os.Message.CREATOR.createFromParcel(data); } else { _arg0 = null ; } this .send(_arg0); return true ; } } return super .onTransact(code, data, reply, flags); } private static class Proxy implements android .os .IMessenger { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } public android.os.IBinder asBinder () { return mRemote; } public java.lang.String getInterfaceDescriptor () { return DESCRIPTOR; } public void send (android.os.Message msg) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((msg != null )) { _data.writeInt(1 ); msg.writeToParcel(_data, 0 ); } else { _data.writeInt(0 ); } mRemote.transact(Stub.TRANSACTION_send, _data, null , android.os.IBinder.FLAG_ONEWAY); } finally { _data.recycle(); } } } static final int TRANSACTION_send = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 ); } public void send (android.os.Message msg) throws android.os.RemoteException ; }
Messenger.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 public final class Messenger implements Parcelable { private final IMessenger mTarget; public Messenger (Handler target) { mTarget = target.getIMessenger(); } public void send (Message message) throws RemoteException { mTarget.send(message); } public IBinder getBinder () { return mTarget.asBinder(); } public boolean equals (Object otherObj) { if (otherObj == null ) { return false ; } try { return mTarget.asBinder().equals(((Messenger)otherObj) .mTarget.asBinder()); } catch (ClassCastException e) { } return false ; } public int hashCode () { return mTarget.asBinder().hashCode(); } public int describeContents () { return 0 ; } public void writeToParcel (Parcel out, int flags) { out.writeStrongBinder(mTarget.asBinder()); } public static final Parcelable.Creator<Messenger> CREATOR = new Parcelable.Creator<Messenger>() { public Messenger createFromParcel (Parcel in) { IBinder target = in.readStrongBinder(); return target != null ? new Messenger(target) : null ; } public Messenger[] newArray(int size) { return new Messenger[size]; } }; public static void writeMessengerOrNullToParcel (Messenger messenger, Parcel out) { out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder() : null ); } public static Messenger readMessengerOrNullFromParcel (Parcel in) { IBinder b = in.readStrongBinder(); return b != null ? new Messenger(b) : null ; } public Messenger (IBinder target) { mTarget = IMessenger.Stub.asInterface(target); } }
ContentProvider&Binder 可以使用ContentProvider结合AIDL的方式实现两个进程之间的通信,这种方式不需要通过bindService来建立两个进程之间的ServiceConnection。
MatrixCursor 在介绍上面的方式之前,可以先看一下 MatrixCursor 这个 Cursor 对象。
在一些使用 Cursor 的场景里,如果想得到一个 Cursor 对象,但又没有数据库返回一个 Cursor,此时可以通过 MatrixCursor 来返回一个伪造的 Cursor。比如一个程序在一般情况下用 context.getContentResolver().query() 从 ContentProvider 中查询数据,但是在一些特殊的场景里,需要返回的只有几条固定的已知记录,不需要从数据库查询,此时可以使用 MatrixCursor 来根据这些已知的记录构造一个 Cursor。
MatrixCursor 的用法如下:
首先创建一个字符数组,字符数组的值对应着表的字段:
1 val COLUMN_NAME = arrayOf("_id" , "name" , "age" )
利用MatrixCursor的构造方法,构造一个MatrixCursor,传入的参数即是步骤1中创建的字段数组:
1 matrixCursor = MatrixCursor(COLUMN_NAME)
通过matrixCursor的addRow方法添加一行值,相当于向数据库中插入一条记录:
1 2 3 matrixCursor?.addRow(arrayOf<Any>(1 , "hearing" , 24 )) matrixCursor?.newRow()?.add(2 )?.add("hhh" )?.add(22 )
通过上面三步即可完成 MatrixCursor 的构造,从 MatrixCursor 中取出数据的过程与 Cursor 相同。
接下来通过一个实例来看看怎么具体地借助 ContentProvider 和 Binder 来进行便捷的跨进程通信。
Server进程 服务端接口定义
在服务端进程或者服务端 App 中,定义 AIDL 接口文件:
1 2 3 interface IMyAidlInterface { int getCount(); }
make 之后实现接口:
1 2 3 4 5 6 class CountServiceImpl : IMyAidlInterface.Stub () { override fun getCount () : Int { println("Server: getCount" ) return 100 } }
ContentProvider定义
接着注册并定义一个运行在服务端进程的 ContentProvider 对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class BinderProvider : ContentProvider () { override fun onCreate () : Boolean = true override fun query ( uri: Uri , projection: Array <out String >?, selection: String ?, selectionArgs: Array <out String >?, sortOrder: String ? ) : Cursor { return BinderCursor.binderCursor } override fun getType (uri: Uri ) : String? = null override fun insert (uri: Uri , values: ContentValues ?) : Uri? = null override fun delete (uri: Uri , selection: String ?, selectionArgs: Array <out String >?) : Int = 0 override fun update (uri: Uri , values: ContentValues ?, selection: String ?, selectionArgs: Array <out String >?) : Int = 0 }
这里 query 方法中返回的 Cursor 对象是一个 BinderCursor.binderCursor, BinderCursor 继承自 MatrixCursor 类,其内保存有服务端 Binder 对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class BinderCursor private constructor () : MatrixCursor(arrayOf("service" )) { companion object { private const val KEY_BINDER_COUNT = "key_binder_count" val binderCursor = BinderCursor() fun getCountService (cursor: Cursor ?) : IBinder? { return cursor?.extras?.getBinder(KEY_BINDER_COUNT) } } private val mBinderExtra = Bundle() init { mBinderExtra.putBinder(KEY_BINDER_COUNT, CountServiceImpl()) } override fun getExtras () : Bundle { return mBinderExtra } }
然后在 Manifest 中注册:
1 2 3 4 5 6 <provider android:name =".server.BinderProvider" android:authorities ="com.hearing.binder.demo" android:exported ="true" android:grantUriPermissions ="true" android:process =":provider" />
Client进程 客户端进程通过以下方法可以获取到 Binder 代理对象,并远程调用服务端接口:
1 2 3 4 5 6 7 8 9 val cursor = contentResolver.query(Uri.parse("content://com.hearing.binder.demo" ), null , null , null , null )try { val service = IMyAidlInterface.Stub.asInterface(BinderCursor.getCountService(cursor)) println("Client: ${service?.count} " ) } catch (e: Exception) { e.printStackTrace() } finally { cursor?.close() }
总结 通过一个AIDL文件实现通用的跨进程接口调用 。