1. Android IPC简介 IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程间进行数据交换的过程。关于进程和线程的区别,在我之前发过的多线程并发总结录(一) – 线程进程基础 中有详细叙述到。在Android程序中有一个主线程叫UI线程,只有在UI线程里面才能操作界面元素。很多时候,如果在UI线程执行很多耗时操作,严重影响了用户的体验,系统就会报出ANR异常(Application Not Responding)即应用无响应。
IPC机制不是Android独有的,任何操作系统都有响应的IPC机制,比如Windows的剪切板,管道都是进程间通信机制;Linux上可以通过命名管道,共享内存,信号量等进行进程间通信。
在Android中常用的进程间通信方式有:Bundle、文件共享、AIDL、Messager、ContentProvider和Socket。
2. IPC基础概念 IPC的基础概念包含三部分内容:Serializable接口,Parcelable接口和Binder。
Serializable和Parcelable接口可以完成对象的序列化过程,然后通过Intent和Binder进行传输。下面我们分别来介绍一下这三者的使用。
2.1 Serializable序列化对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Student implements Serializable { private static final long serialVersionUID = 123456789L ; private String name; private boolean sex; private int age; ...... } Student student = new Student("JackOu" , true , 18 ); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test.txt" )); out.writeObject(student); out.close(); ObjectInputStream in = new ObjectInputStream(new FileInputStream("test.txt" )); Student student1 = (Student) in.readObject(); in.close();
注意: serialVersionUID为任意值都可以,但是序列化前的对象和反序列化对象的serialVersionUID必须一致,否则会报异常。因为序列化的时候,系统会把serialVersionUID写入到文件中,在反序列化的时候,会对比这个值,如果不一样,就说明这个对象被修改过,不是同一版本的,所以会报异常。
1 2 java.io.InvalidClassException: com.gacrnd.gcs.ipc.Student; local class incompatible: stream classdesc serialVersionUID = 123456789, local class serialVersionUID = 123789
2.2 Parcelable序列化对象 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 public class Person implements Parcelable { private String name; private int age; public Person (String name,int age) { this .name = name; this .age = age; } protected Person (Parcel in) { name = in.readString(); age = in.readInt(); } @Override public void writeToParcel (Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } @Override public int describeContents () { return 0 ; } public static final Creator<Person> CREATOR = new Creator<Person>() { @Override public Person createFromParcel (Parcel in) { return new Person(in); } @Override public Person[] newArray(int size) { return new Person[size]; } }; }
2.3 Serializable和Parcelable区别 Serializable和Parcelable都可以实现序列化,那么他们有什么区别呢。
如果使用基于Binder实现的通信方式,一般选择Parcelable效率比较高;如果将序列化对象存储在设备中或者通过网络进行传输,选择Serializable比较方便。
2.4 Binder通信 1 2 3 4 package com.gacrnd.gcs.ipc;parcelable Book;
1 2 3 4 5 6 7 8 9 package com.gacrnd.gcs.ipc;import com.gacrnd.gcs.ipc.Book; interface IBookManager { List<Book> getBookList () ; void addBook (in Book book) ; }
服务端实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private final IBookManager.Stub mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList () throws RemoteException { synchronized (mBookList) { return mBookList; } } @Override public void addBook (Book book) throws RemoteException { synchronized (mBookList) { if (!mBookList.contains(book)) { mBookList.add(book); } } } };
客户端实现
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 public class MainActivity extends AppCompatActivity { IBookManager mService; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(this ,MyService.class); bindService(intent,sconn, Context.BIND_AUTO_CREATE); } private ServiceConnection sconn = new ServiceConnection() { @Override public void onServiceConnected (ComponentName name, IBinder service) { mService = IBookManager.Stub.asInterface(service); } @Override public void onServiceDisconnected (ComponentName name) { mService = null ; } }; }
关于Binder最简单的使用就是上面的代码,后面分析framework的时候会详细分析Binder的具体实现。
另外当客户端和服务端断开的希望接收到通知,我们可以实现一个DeathRecipient对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied () { if (mService == null ) { return ; } mService.asBinder().unlinkToDeath(mDeathRecipient, 0 ); mService = null ; } }; public void onServiceConnected (ComponentName name, IBinder service) { mService = IBookManager.Stub.asInterface(service); service.linkToDeath(mDeathRecipient,0 ); }
参考文档:
《Android开发艺术探索》