Android进阶-IPC机制
一.背景:
一个应用默认只在一个进程中运行,当两个进程需要进行通信时不能像平常一样传递数据,因为每个进程都有它自己的虚拟地址空间,两个进程虽然有相同的虚拟地址,但是这两个虚拟地址被映射到的实际的物理地址却不尽相同,这时就需要有进程间通信机制。在Android下,常见的IPC机制有:
1. Bundle
2. 文件共享
3. Messager
4. AIDL
5. ContentProvider
6. Socket
这里主要记录AIDL的一些知识。
二.AIDL的使用:
1. 创建接口
在/src/main/aidl/pacage name/下新建IBookManager.aidl
1 package com.dhn.learnaidl; 2 3 interface IBookManager { 4 List<String> getBookList(); 5 void addBook(String book); 6 }
sync工程,
自动生成IBookManager.java:
1 package com.dhn.learnaidl; 2 3 public interface IBookManager extends android.os.IInterface { 4 /** 5 * Local-side IPC implementation stub class. 6 */ 7 public static abstract class Stub extends android.os.Binder implements com.dhn.learnaidl.IBookManager { 8 private static final java.lang.String DESCRIPTOR = "com.dhn.learnaidl.IBookManager"; 9 10 /** 11 * Construct the stub at attach it to the interface. 12 */ 13 public Stub() { 14 this.attachInterface(this, DESCRIPTOR); 15 } 16 17 /** 18 * Cast an IBinder object into an com.dhn.learnaidl.IBookManager interface, 19 * generating a proxy if needed. 20 */ 21 public static com.dhn.learnaidl.IBookManager asInterface(android.os.IBinder obj) { 22 if ((obj == null)) { 23 return null; 24 } 25 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 26 if (((iin != null) && (iin instanceof com.dhn.learnaidl.IBookManager))) { 27 return ((com.dhn.learnaidl.IBookManager) iin); 28 } 29 return new com.dhn.learnaidl.IBookManager.Stub.Proxy(obj); 30 } 31 32 @Override 33 public android.os.IBinder asBinder() { 34 return this; 35 } 36 37 @Override 38 public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { 39 switch (code) { 40 case INTERFACE_TRANSACTION: { 41 reply.writeString(DESCRIPTOR); 42 return true; 43 } 44 case TRANSACTION_getBookList: { 45 data.enforceInterface(DESCRIPTOR); 46 java.util.List<java.lang.String> _result = this.getBookList(); 47 reply.writeNoException(); 48 reply.writeStringList(_result); 49 return true; 50 } 51 case TRANSACTION_addBook: { 52 data.enforceInterface(DESCRIPTOR); 53 java.lang.String _arg0; 54 _arg0 = data.readString(); 55 this.addBook(_arg0); 56 reply.writeNoException(); 57 return true; 58 } 59 } 60 return super.onTransact(code, data, reply, flags); 61 } 62 63 private static class Proxy implements com.dhn.learnaidl.IBookManager { 64 private android.os.IBinder mRemote; 65 66 Proxy(android.os.IBinder remote) { 67 mRemote = remote; 68 } 69 70 @Override 71 public android.os.IBinder asBinder() { 72 return mRemote; 73 } 74 75 public java.lang.String getInterfaceDescriptor() { 76 return DESCRIPTOR; 77 } 78 79 @Override 80 public java.util.List<java.lang.String> getBookList() throws android.os.RemoteException { 81 android.os.Parcel _data = android.os.Parcel.obtain(); 82 android.os.Parcel _reply = android.os.Parcel.obtain(); 83 java.util.List<java.lang.String> _result; 84 try { 85 _data.writeInterfaceToken(DESCRIPTOR); 86 mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); 87 _reply.readException(); 88 _result = _reply.createStringArrayList(); 89 } finally { 90 _reply.recycle(); 91 _data.recycle(); 92 } 93 return _result; 94 } 95 96 @Override 97 public void addBook(java.lang.String book) throws android.os.RemoteException { 98 android.os.Parcel _data = android.os.Parcel.obtain(); 99 android.os.Parcel _reply = android.os.Parcel.obtain(); 100 try { 101 _data.writeInterfaceToken(DESCRIPTOR); 102 _data.writeString(book); 103 mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); 104 _reply.readException(); 105 } finally { 106 _reply.recycle(); 107 _data.recycle(); 108 } 109 } 110 } 111 112 static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 113 static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); 114 } 115 116 public java.util.List<java.lang.String> getBookList() throws android.os.RemoteException; 117 118 public void addBook(java.lang.String book) throws android.os.RemoteException; 119 }
将该类画成UML图:
2.完成服务端代码:
1 public class BookManagerService extends Service { 2 3 private List<String> mBookList = new ArrayList<String>(); 4 private Binder mBinder = new IBookManager.Stub(){ 5 6 @Override 7 public List<String> getBookList() throws RemoteException { 8 return mBookList; 9 } 10 11 @Override 12 public void addBook(String book) throws RemoteException { 13 mBookList.add(book); 14 } 15 }; 16 17 public BookManagerService() { 18 } 19 20 @Override 21 public void onCreate() { 22 super.onCreate(); 23 mBookList.add("book1"); 24 mBookList.add("book2"); 25 mBookList.add("book3"); 26 } 27 28 @Override 29 public IBinder onBind(Intent intent) { 30 return mBinder; 31 } 32 }
3.客户端代码:
1 public class MainActivity extends AppCompatActivity implements ServiceConnection{ 2 3 private final String TAG = "MAIN"; 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_main); 8 9 Intent intent = new Intent(this, BookManagerService.class); 10 bindService(intent, this, BIND_AUTO_CREATE); 11 } 12 13 14 @Override 15 public void onServiceConnected(ComponentName name, IBinder service) { 16 //将IBookManaver.Stub对象转换为IBookManager.Stub.Proxy对象 17 IBookManager bookManager = IBookManager.Stub.asInterface(service); 18 19 try { 20 //从Service所在的进程返回数据 21 List<String> list = bookManager.getBookList(); 22 Log.e(TAG, "从Service进程返回的书单:" + list.toString()); 23 bookManager.addBook("book4"); 24 list = bookManager.getBookList(); 25 Log.e(TAG, "添加一本书后返回的书单:" + list.toString()); 26 27 28 } catch (RemoteException e) { 29 e.printStackTrace(); 30 } 31 } 32 33 @Override 34 public void onServiceDisconnected(ComponentName name) { 35 36 } 37 }
4.运行结果:
1 E/MAIN: 从Service进程返回的书单:[book1, book2, book3] 2 E/MAIN: 添加一本书后返回的书单:[book1, book2, book3, book4]
三.原理分析:
客户端调用BindService(),在onServiceConnected()中获得从服务端Service返回的IBookManager.Stub对象(客户端和服务端各有一个IBookManager.Stub对象),调用IBookManager.Stub.asInterface(service),在不同进程的情况下该方法返回的是IBookManager.Stub.Proxy对象(即IBookManager.Stub的代理类)。然后使用该对象调用bookManager.getBookList()获取服务端提供的服务,从生成的代码中看出该方法调用mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0)方法,mRemote是IBookManager.Stub对象(由UML图,IBookManager.Stub继承Binder,重写了Binder.onTranscat()),该方法接着调用IBookManager.Stub.onTransect()方法,该方法挂起客户端进程,根据传入的方法代号在服务端的Binder线程池中选择运行指定的服务,这里是自己实现的getBookList()方法。运行结束后结果从mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0)返回,当前线程继续运行。这样就完成了一次进程间通信。