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)返回,当前线程继续运行。这样就完成了一次进程间通信。

posted @ 2016-03-29 16:21  gatsbydhn  阅读(224)  评论(0编辑  收藏  举报