什么是Binder?
从IPC角度:它是Android的一种跨进程通信方式,
从fromwork角度:它是ServiceManager联系各种Manager和相应ManagerService的桥梁
从应用层角度:是客户端和服务端通信的媒介。
在Android开发中,BInder主要用于Service中,包括AIDL和Messenger,其中普通Service中的Binder不涉及跨进程通讯,而Messager的底层是AIDL,所以我么通过AIDL来了解Binder.
注:我们需要使用Binder和Intent传输数据的时候,传输的数据序列化,不熟悉的可以过一遍我之前的笔记
序列化之serializable和parcelable的区别
新建三个文件Book.java、Book.aidl、IBookManager.aidl
- Book.java
就是个java类,注意实现parcelable就行了。
public class Book implements Parcelable{
private int bookId;
private String bookName;
public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
}
- IBookManager.aidl
声明了两个方法
ps:新建的aid文件都会默认有个方法,注释/删除掉就行了。
// IBookManager.aidl
package com.demo.nick.ipcstudy;
// Declare any non-default types here with import statements
import com.demo.nick.ipcstudy.Book;
interface IBookManager {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
// void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
// double aDouble, String aString);
List getBookList();
void addBook(in Book book);
}
- Book.aidl
在AIDL中声明parcelable 类Book;
注意:这里如果你先建了Book.java 在直接new aidl会提示 interface Name must be unique
解决办法:可以先创建Book.adil文件,也可以先任意文件名,创建好了在改。
// IBook.aidl
package com.example.nick.ipcdemoone.aidl;
// Declare any non-default types here with import statements
parcelable Book;
重行build下,系统会为我们生成一个binder文件
下面看它内部代码(我改了下代码结构顺序,方便阅读)
首先它声明了两个方法,就是我们之前创建AIDL文件时定义的方法。然后有个内部类Stub,继承了Binder类,Stub自己也有个内部类代理Proxy。具体方法解释我放在注释里。
package com.demo.nick.ipcstudy;
public interface IBookManager extends android.os.IInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public java.util.List getBookList() throws android.os.RemoteException;
public void addBook(com.demo.nick.ipcstudy.Book book) throws android.os.RemoteException;
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.demo.nick.ipcstudy.IBookManager {
//binder的唯一标识
private static final java.lang.String DESCRIPTOR = "com.demo.nick.ipcstudy.IBookManager";
//方法的标识
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.demo.nick.ipcstudy.IBookManager interface,
* generating a proxy if needed.
* 用于将服务端的Binder对象转换成客户端所需要的AIDL接口类型的对象,
* 如果在客户端和服务端在同一进程,则返回的就是stub本身,否则返回封装后的Stub.proxy对象
*/
public static com.demo.nick.ipcstudy.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.demo.nick.ipcstudy.IBookManager))) {
return ((com.demo.nick.ipcstudy.IBookManager) iin);
}
return new com.demo.nick.ipcstudy.IBookManager.Stub.Proxy(obj);
}
//返回当前Binder对象
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 运行在Binder线程池中,当client发起跨进程请求时(也就是说不跨进程不会调用),会调用该方法,
*
* @param code 确定服务端的目标方法
* @param data 取出目标方法所需要的参数(有参数的话),然后调用该目标方法。
* @param reply 写入返回值
* @param flags
* @return false则请求失败,
* @throws android.os.RemoteException
*/
@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_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.demo.nick.ipcstudy.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.demo.nick.ipcstudy.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.demo.nick.ipcstudy.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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
* 运行在client
*/
@Override
public java.util.List getBookList() throws android.os.RemoteException {
//创建两个parcel对象。前者用于输入,后者用于输出
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List _result;//返回结果
try {
_data.writeInterfaceToken(DESCRIPTOR);
//发起请求
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
//读取返回结果---无返回值则不用
_result = _reply.createTypedArrayList(com.demo.nick.ipcstudy.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.demo.nick.ipcstudy.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);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
}
}
一个完成的流程就是这样
客户端调用方法,getBookList(),然后
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
调起服务端。走onTransact
方法。
_result = _reply.createTypedArrayList(com.demo.nick.ipcstudy.Book.CREATOR);
获得结果
这里只是binder的运行机制,没有头和尾对不对,
下面看一个完整的通过AIDL实现的IPC通信
https://www.jianshu.com/p/db11290d64e3