我是靠谱客的博主 哭泣金毛,这篇文章主要介绍Android进程通信之AIDL的使用与Binder浅谈,现在分享给大家,希望可以做个参考。

一、AIDL简介

AIDL是Android接口定义语言,有点类似于我们开发中的普通接口。由于不同进程间不能共享内存,为了解决进程间通信的问题,可以通过AIDL接口语言来实现进程间的通信。

二、AIDL文件支持的数据类型

  • 基本数据类型(int、long、char、boolean、double)
  • String和CharSequence
  • List和Map集合
  • 集合内元素必须是AIDL支持的数据类型
  • 服务端具体使用的集合必须是ArrayList和HashMap
  • Parcelable:实现了Parcelable接口的对象
  • AIDL本身接口也可以在AIDl文件使用。

三、AIDL使用步骤

主要有三大步骤

  1. 创建AIDL
    (1)创建实例类,必须实现Parcelable接口,用于序列化和反序列化
    (2)新建aidl文件夹,在其创建与实例类同名的aidl文件及其他aidl接口文件
    (3)rebuild项目,生成Binder的java接口文件。
  2. 创建服务端(Service)
    (1)创建Service,在onBind方法中返回Binder实例对象,并实现aidl接口方法。
  3. 编写客服端(Activity或其他)
    (1)使用bindService方式启动服务,实现ServiceConnection接口,拿到aidl生成的Binder对象。
    (2)调用aidl定义好的函数方法。

四、AIDL具体实现

为了方便AIDL的开发,建议所有和AIDL相关的类和文件全部放在同一个包,这样方便其他地方需要使用,可以直接复制过去。
下面是具体例子的文件目录:
在这里插入图片描述
注意:

aidl文件目录是和java目录同级的

1、创建AIDL
1.1、创建进程间需要传输的实体类,实现 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
40
41
42
public class Book implements Parcelable{ private String bookName; public Book(String bookName) { this.bookName = bookName; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.bookName); } protected Book(Parcel in) { this.bookName = in.readString(); } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel source) { return new Book(source); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public String toString() { return "Book{" + "bookName='" + bookName + ''' + '}'; } }

实现 Parcelable 接口是为了实例类能够在进程间通信。
其实进程间通信是一个序列化和反序列化的过程,关于序列化可以参考这篇文章Android进程通信之文件共享(序列化Serialzable与Parcelable)

1.2、新建aidl文件夹,在其创建与实例类同名的aidl文件及其他aidl接口文件
  • 新建aidl文件夹,主要aidl目录和java目录是同级的,在main目录下面。
    在这里插入图片描述
  • 创建与实体类(Book)同名的aidl文件:Book.aidl
复制代码
1
2
3
4
5
6
// Book.aidl package com.hzw.progress.aidl; //声明Book实体类已序列化,可用于进程间传输 parcelable Book;

这样做的目的是让aidl文件知道Book类实现了Parcelable接口,可将Book对象作为进程间传输数据的载体。

注意:

Book实体类和Book.aidl文件必须要在相同包结构目录下,否则会运行出错,是因为客服端需要反序列化服务端的AIDL接口相关的类,如果类的路径不一样的话,客户端会反序列失败。

IBookManager.aidl接口

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// IBookManager.aidl package com.hzw.progress.aidl; // Declare any non-default types here with import statements //虽然在IBookManager.aidl和Book.aidl同一个包名下,但必须以import方式将Book.aial文件导入(手动导入) import com.hzw.progress.aidl.Book; import com.hzw.progress.aidl.OnNewBookAddListener; //定义客户端与服务端间的回调接口 interface IBookManager { //得到全部数据(全部书籍) List<Book> getBookList(); //添加数据的操作(添加书籍) void addBook(in Book book); //注册监听,用于监听新数据的变化。是典型的观察者模式的运用 void registerListener(OnNewBookAddListener listener); //解注册 void unregisterListener(OnNewBookAddListener listener); }

OnNewBookAddListener.aidl接口文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// OnNewBookAddListener.aidl package com.hzw.progress.aidl; import com.hzw.progress.aidl.Book; // Declare any non-default types here with import statements //定义监听新数据变化的接口(添加新书籍) interface OnNewBookAddListener { void onNewBookAdd(in Book book); void onAllBook(); }

以上需要注意的点,在addBook和onNewBookAdd方法接参中有个in,表示输入型参数。AIDL 中除了基本数据类型,其他数据类型必须标上方向,in,out 或者 inout。

  • in 表示输入型参数
  • out 表示输出型参数
  • inout 表示输入输出型参数
1.3 在创建好了aidl文件后,需要 rebuild项目,生成Binder的java接口文件。
2、创建服务端
2.1、创建服务端BookManagerService继承于Service
复制代码
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
118
119
120
121
122
123
124
125
126
127
128
public class BookManagerService extends Service { private static final String TAG = "BookManagerService"; private List<Book> mBookList=new ArrayList<>(); private static List<OnNewBookAddListener> mAddListenerList=new ArrayList<>(); public BookManagerService() { } @Override public void onCreate() { super.onCreate(); //初始化书籍 mBookList.add(new Book("Android群英传")); mBookList.add(new Book("Android开发艺术探索")); } @Override public IBinder onBind(Intent intent) { //获取Service需要的权限,进行自我验证,防止其他进程访问该服务 int check= checkCallingOrSelfPermission("com.hzw.progress.aidl.permission.LOCAL"); //未授权该应用,则无法访问 if (check== PackageManager.PERMISSION_DENIED){ return null; } //添加新书的过程 BookFactory factory = new BookFactory(); factory.execute(5); //添加五本书 return mBinder; } /* * 初次new IBookManager方式构建Binder对象,会报错找不到IBookManager对象 * 需要Rebuild下项目 * */ private Binder mBinder=new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { return mBookList; } @Override public void addBook(Book book) throws RemoteException { mBookList.add(book); } @Override public void registerListener(OnNewBookAddListener listener) throws RemoteException { if (!mAddListenerList.contains(listener)){ mAddListenerList.add(listener); } Log.i(TAG, "registerListener: "+mAddListenerList.size()); } @Override public void unregisterListener(OnNewBookAddListener listener) throws RemoteException { if (mAddListenerList.contains(listener)){ mAddListenerList.remove(listener); } } }; /** * 使用静态内部类,避免泄漏 */ private static class BookFactory extends AsyncTask<Integer,Book,Book>{ @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Book doInBackground(Integer... integers) { //每隔2秒添加新建一本新书,最多只能添加5本 int i=0; Book mBook=null; while (i< integers[0]){ mBook=new Book("新书"+(i+1)); try { Thread.sleep(2000); publishProgress(mBook); i++; } catch (InterruptedException e) { e.printStackTrace(); } } return mBook; } @Override protected void onProgressUpdate(Book... values) { super.onProgressUpdate(values); //监听每次添加数据内容 for (int i = 0; i <mAddListenerList.size() ; i++) { OnNewBookAddListener listener = mAddListenerList.get(i); try { if (listener!=null){ listener.onNewBookAdd(values[0]); } } catch (RemoteException e) { e.printStackTrace(); } } } @Override protected void onPostExecute(Book book) { super.onPostExecute(book); //得到全部的书籍 for (int i = 0; i <mAddListenerList.size() ; i++) { OnNewBookAddListener listener = mAddListenerList.get(i); try { if (listener!=null){ listener.onAllBook(); } } catch (RemoteException e) { e.printStackTrace(); } } } } }

服务端是Service的典型实现,具体使用可以参考这篇文章Service实例深入理解,以上需要注意的点:

  • 在onBind方法中,最好添加访问权限的判断,防止一些恶意的访问,可使用 Permission 验证,在 manifest 中声明。
  • 创建Binder 对象时,不能使用new Binder ()的方式,必须使用new IBookManager.Stub()创建Binder对象,这是AIDL接口文件自动生成的Binder对象。

最后需要在Mainfest文件中注册Service,同时自定义定义服务端的访问权限并引用。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
<!--自定义访问Service的权限--> <permission android:name="com.hzw.progress.aidl.permission.LOCAL"/> <!--声明本拥有该权限--> <uses-permission android:name="com.hzw.progress.aidl.permission.LOCAL"/> <service android:name=".aidl.BookManagerService" android:enabled="true" android:exported="true" android:process=":remote" android:permission="com.hzw.progress.aidl.permission.LOCAL"> </service>

注意:

BookManagerService要在独立进程中需要,必须定义属性 android:process=”:remote”

3、编写客服端

绑定远程服务后,通过ServiceConnection得到代理对象Binder,同时将Binder对象转换成AIDL接口,然后通过AIDL接口去调用服务端的方法。

复制代码
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
public class AIDLActivity extends AppCompatActivity { private static final String TAG = "AIDLActivity"; private Intent mIntent; private IBookManager mIBookManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_aidl); mIntent = new Intent(this, BookManagerService.class); } public void onClick(View view) { switch (view.getId()){ case R.id.bindService: //绑定服务 bindService(mIntent,mConnection,BIND_AUTO_CREATE); break; case R.id.unbindService: //解绑服务 unbindService(mConnection); break; } } private ServiceConnection mConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { try { //ClassCastException // IBookManager iBookManager=(IBookManager)service; mIBookManager = IBookManager.Stub.asInterface(service); mIBookManager.addBook(new Book("Android进阶之光")); List<Book> bookList = mIBookManager.getBookList(); // Log.i(TAG, "全部书籍: "+bookList.toString()); mIBookManager.registerListener(sListener); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); try { mIBookManager.unregisterListener(sListener); } catch (RemoteException e) { e.printStackTrace(); } } private OnNewBookAddListener sListener=new OnNewBookAddListener.Stub() { @Override public void onNewBookAdd(Book book) throws RemoteException { mIBookManager.addBook(book); Log.i(TAG, "onNewBookAdd: "+book.toString()); } @Override public void onAllBook() throws RemoteException { List<Book> bookList = mIBookManager.getBookList(); Log.i(TAG, "onAllBook: "+bookList.toString()); } }; }

以上就是客户端的基本实现,需要注意一下几点:

  • 在得到代理对象Binder时,不能直接使用强转的方式,否则会报类型转换异常,必须使用IBookManager.Stub.asInterface()得到AIDL接口文件生成的Binder对象。
  • 在需得到一个AIDl接口实例对象,需要.Stub()方法得到实例。

以上三大步骤就是AIDL实现进程通信的简单例子,运行结果如下:

复制代码
1
2
3
4
5
6
7
8
9
07-14 17:59:47.974 6970-6988/com.hzw.progress I/AIDLActivity: onNewBookAdd: Book{bookName='新书1'} 07-14 17:59:49.974 6970-6989/com.hzw.progress I/AIDLActivity: onNewBookAdd: Book{bookName='新书2'} 07-14 17:59:51.974 6970-6988/com.hzw.progress I/AIDLActivity: onNewBookAdd: Book{bookName='新书3'} 07-14 17:59:53.975 6970-6989/com.hzw.progress I/AIDLActivity: onNewBookAdd: Book{bookName='新书4'} 07-14 17:59:55.976 6970-6988/com.hzw.progress I/AIDLActivity: onNewBookAdd: Book{bookName='新书5'} 07-14 17:59:55.977 6970-6989/com.hzw.progress I/AIDLActivity: onAllBook: [Book{bookName='Android群英传'}, Book{bookName='Android开发艺术探索'}, Book{bookName='Android进阶之光'}, Book{bookName='新书1'}, Book{bookName='新书2'}, Book{bookName='新书3'}, Book{bookName='新书4'}, Book{bookName='新书5'}]

五、AIDL使用注意点:

  • AIDL接口文件的包结构必须与实体类的同结构,否则会反序列化失败
  • 与实体类同名的AIDL接口文件,必须使用parcelable声明Book类已序列化,注意全是小写
  • 在一个AIDL文件中使用另外一个AIDL文件时,需手工显式(全包名)导入。

以上任何一个点不小心搞错的话,AIDL就无法实现进程通信。

六、AIDL使用解析

上面的例子基本实现了AIDL进程间的通信,其中还存在很多疑问,比如:

  1. AIDL 在实现通信过程中具体做哪些内容?
  2. 服务端创建Binder对象或者得到AIDL接口对象,都在调用Stub()方法实现,那么该方法具体有哪些操作?
  3. 什么是Binder?

其实上面这三点可以统称理解为AIDL本质是什么;下面重点对AIDL文件生成的java文件进行解析,在创建了AIDL文件后SDK会自动生成对应的Binder类,可以简单理解为AIDL是一种实现Binder的工具。

  • 从接口层面,Binder是Android中的一个类,它实现了IBinder接口
  • 从应用层面,Binder是客户端和服务端进行通信的中间代理,当bindService后,服务端会返回一个代理对象Binder,通过其可以获取服务端的数据。
  • 从IPC层面,Binder是Android中的一种跨进程通信方式
  • 从底层角度,Binder是连接各种Manager(ActivityManager、WindowManager等)的桥梁
  • 从物理层面,Binder是一种虚拟的物理设备,有自己的驱动设备。

七、AIDL原理

在上篇的例子中我们创建了两个aidl文件,分别是IBookManager.aidl、OnNewBookAddListener.aidl文件,在rebuild编译项目后,会自动生成对应的java文件,如下:
在这里插入图片描述
打开对应的java文件,下面以IBookManager.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
/* * This file is auto-generated. DO NOT MODIFY. * Original file: F:\StudyAndroid\progress\src\main\aidl\com\hzw\progress\aidl\IBookManager.aidl */ package com.hzw.progress.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.hzw.progress.aidl.IBookManager { private static final java.lang.String DESCRIPTOR = "com.hzw.progress.aidl.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.hzw.progress.aidl.IBookManager interface, * generating a proxy if needed. */ public static com.hzw.progress.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.hzw.progress.aidl.IBookManager))) { return ((com.hzw.progress.aidl.IBookManager) iin); } return new com.hzw.progress.aidl.IBookManager.Stub.Proxy(obj); } private static class Proxy implements com.hzw.progress.aidl.IBookManager { *********************省略******************** } } public java.util.List<com.hzw.progress.aidl.Book> getBookList() throws android.os.RemoteException; public void addBook(com.hzw.progress.aidl.Book book) throws android.os.RemoteException; public void registerListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException; public void unregisterListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException; }

以上的代码很多,我们可以通过类的树形结构图大体知道AIDL文件生成java文件的基本信息及内容:
在这里插入图片描述

  • IBookManager.java这个类是一个接口,继承于IInterface这个接口
  • 接着声明了一个内部类Stub,而这个Stub是继承于Binder,就是一个Binder对象;同时实现了IBookManager本身的实例。
  • 同时也声明了在aidl文件定义的四个方法,分别是:getBookList、addBook、registerListener、unregisterListener

从整个代码结构可以看出,IBookManager类的具体功能在内部类Stub实现的,接下来就看看内部类Stub的逻辑,

复制代码
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 static abstract class Stub extends android.os.Binder implements com.hzw.progress.aidl.IBookManager { //Binder的唯一标识,一般是以当前Binder的类名表示 private static final java.lang.String DESCRIPTOR = "com.hzw.progress.aidl.IBookManager"; //将IBookManager接口关联到Binder对象中 public Stub() { this.attachInterface(this, DESCRIPTOR); } //将服务端的Binder对象转换成客户端需要的接口对象IBookManager。 public static com.hzw.progress.aidl.IBookManager asInterface(android.os.IBinder obj) { //判断obj是否null,为null则说明客户端与服务端连接失败 if ((obj == null)) { return null; } //通过标识查询obj对象是否有关联的接口 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); //不为null,说明服务端和客户端在同一个进程中,返回自身对象 if (((iin != null) && (iin instanceof com.hzw.progress.aidl.IBookManager))) { return ((com.hzw.progress.aidl.IBookManager) iin); } //为null,则返回一个Binder的代理对象Proxy return new com.hzw.progress.aidl.IBookManager.Stub.Proxy(obj); }

Stub类是继承于Binder类,同时实现了IBookManager接口,定义了两个自身的函数分别是构造函数Stub和asInterface:

  • 通过构造函数 Stub()将IBookManager接口关联到Binder对象中,通过传入DESCRIPTOR 字段标识当前Binder对象,保证Binder对象的唯一性。
  • 通过asInterface函数将服务端的Binder对象转换成客户端需要的接口对象IBookManager,从而实现客户端与服务端的交互。
    在这里插入图片描述

asInterface方法有以下几个流程逻辑:

  • 首先会判断传入的binder对象是否为null,若为null,说明客户端和服务端没有建立连接。
  • 接着会拿着DESCRIPTOR 标识去查询binder对象是否有本地对应的接口(通过queryLocalInterface返回值判断)。
  • 最后根据queryLocalInterface返回值判断返回具体的AIDL接口对象,若返回值存在,则返回服务端对象本身Stub,若为null,则返回系统封装好的代理对象Stub.Proxy。

接下看看queryLocalInterface方法的源码

复制代码
1
2
3
4
5
6
7
8
/** * Attempt to retrieve a local implementation of an interface * for this Binder object. If null is returned, you will need * to instantiate a proxy class to marshall calls through * the transact() method. */ public IInterface queryLocalInterface(String descriptor);

从源码的注释可以知道一个大概,通过descriptor标识会先尝试获取本地的binder对象,所谓本地的是指客户端和服务端同属一个进程。如果返回值为null,则需要实例化一个代理对象。我们也可以通过测试来在不同进程queryLocalInterface具体返回情况

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private ServiceConnection mConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { try { mIBookManager = IBookManager.Stub.asInterface(service); IInterface queryLocalInterface = service.queryLocalInterface("com.hzw.progress.aidl.IBookManager"); if (queryLocalInterface!=null){ //客户端与服务端同一个进程 Log.i(TAG, "queryLocalInterface 不为null"); }else { //不同进程 Log.i(TAG, "queryLocalInterface 为null"); } }

既然在不同进程时,asInterface会返回一个Stub.Proxy代理对象,就看看Proxy对象是怎么样的

复制代码
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
private static class Proxy implements com.hzw.progress.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.hzw.progress.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.hzw.progress.aidl.Book> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.hzw.progress.aidl.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.hzw.progress.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); } //执行远程Rcp请求,向服务端发送请求 mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void registerListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null))); mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void unregisterListener(com.hzw.progress.aidl.OnNewBookAddListener listener) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null))); mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } }

Proxy 代理类同样也实现了IBookManager接口,同时也实现了IBookManager类中所有方法。代理类的方法是在客户端调用的,客户端可以通过代理Proxy对象调用相应的方法getBookList、addBook等等。内部实现大概流程如下:

  • 获取输入型Parcel包对象_data和输出型Parcel包对象_reply;
  • 如果方法传入的参数不为null,则将其参数信息写入_data对象中,其实是个对象序列化过程
  • 接着通过远程Binder对象调用transact方法来发送RPC(远程过程调用)请求,同时当前线程会被挂起;
  • 最后,服务端的onTransact会被调用,当服务端处理完请求后,会返回数据,当前线程继续执行知道返回 _result结果。返回数据的过程其实就是一个反序列化过程

在第三步开始,当客户端向服务端发送远程请求,服务端接受到请求,会回调Binder的onTransact方法,并将数据返回给客户端,接下来就看看onTransact的实现逻辑是如何的:

复制代码
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
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { //根据客户端发起请求code,来确定执行 switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List<com.hzw.progress.aidl.Book> _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { //从输入型对象取出参数信息 data.enforceInterface(DESCRIPTOR); com.hzw.progress.aidl.Book _arg0; //读取数据 if ((0 != data.readInt())) { //传入参数存在,则反序列化过程 _arg0 = com.hzw.progress.aidl.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } case TRANSACTION_registerListener: { data.enforceInterface(DESCRIPTOR); com.hzw.progress.aidl.OnNewBookAddListener _arg0; _arg0 = com.hzw.progress.aidl.OnNewBookAddListener.Stub.asInterface(data.readStrongBinder()); this.registerListener(_arg0); reply.writeNoException(); return true; } case TRANSACTION_unregisterListener: { data.enforceInterface(DESCRIPTOR); com.hzw.progress.aidl.OnNewBookAddListener _arg0; _arg0 = com.hzw.progress.aidl.OnNewBookAddListener.Stub.asInterface(data.readStrongBinder()); this.unregisterListener(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); }

当客户端发起跨进程请求时,远程服务端会通过系统底层封装好的方法来处理返回数据,这个就是方法就是onTransact,它内部大概流程如下:

  • 首次会根据客户端请求code来确定需要执行的内容是什么
  • 接着从输入型对象data中取出目标参数,如果参数存在,则进行反序列化操作。
  • 当目标方法执行完毕后,就向输出型reply对象写入数据,并将数据返回给Binder对象,最后返回给客户端。

上面就是整个AIDL实现进程通信的原理流程。

总结

下面简单总结Binder的工作机制

在这里插入图片描述

Binder的工作流程可以分为三部分,分别是连接请求、序列化写入数据、反序列化结果返回客户端

  1. 绑定服务建立连接后,服务端会返回一个Binder对象给客户端,通过Binder对象就可以跨进程交互。在获取Binder实例对象时,需调用asInterface方法进行判断客户端和服务端是否在同一进程,若在同一个进程,则返回一个本地binder对象,反之则需创建一个代理对象Stub.Proxy返回。
  2. 获取到代理对象Proxy后,客户端可以调用服务端相应的方法(addBook、getBookList等)传入参数,当Binder拿到数据后,会根据参数的有无(序列化过程)写入包裹类Parcel中,接着调用binder对象的transact方法。
  3. 最后会触发Stub类(Binder类)的onTransact方法,从线程池中取出数据,写入reply中把结果返回给客户端,最终唤醒线程。

参考Android开发艺术探索

最后

以上就是哭泣金毛最近收集整理的关于Android进程通信之AIDL的使用与Binder浅谈的全部内容,更多相关Android进程通信之AIDL内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(77)

评论列表共有 0 条评论

立即
投稿
返回
顶部