《Android 开发艺术探索》Binder机制阅读笔记
项目代码
java代码部分
activity
public class AidlTestActivity extends AppCompatActivity {
private AidlTestInterface aidlTestInterface;
private int index = 0;
private static final String TAG = "AidlTestActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_aidl_test);
bindService(new Intent(this, AidlTestService.class), connection, BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d(TAG, "onServiceConnected: ");
aidlTestInterface = AidlTestInterface.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d(TAG, "onServiceDisconnected: ");
}
};
@Override
protected void onDestroy() {
super.onDestroy();
}
public void onclick(View view) {
try {
switch (view.getId()) {
case R.id.button3:
index++;
aidlTestInterface.addBook(new Book("书籍" + index, index, "作者" + index));
break;
case R.id.button4:
List<Book> bookList = aidlTestInterface.getBookList();
Toast.makeText(AidlTestActivity.this.getBaseContext(), "现在有书籍" + bookList, Toast.LENGTH_SHORT).show();
for (Book book : bookList) {
Log.d(TAG, "onclick: "+book.toString());
}
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Service
public class AidlTestService extends Service {
private List<Book> books = new ArrayList<>();
public AidlTestService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return stub;
}
AidlTestInterface.Stub stub = new AidlTestInterface.Stub() {
@Override
public void addBook(Book book) throws RemoteException {
books.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
return books;
}
};
}
实体类(BOOK)
public class Book implements Parcelable {
private String bookName;
private int id;
private String auth;
public Book(String bookName, int id, String auth) {
this.bookName = bookName;
this.id = id;
this.auth = auth;
}
protected Book(Parcel in) {
bookName = in.readString();
id = in.readInt();
auth = in.readString();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@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 parcel, int i) {
parcel.writeString(auth);
parcel.writeInt(id);
parcel.writeString(bookName);
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", id=" + id +
", auth='" + auth + '\'' +
'}';
}
}
AIDL
实体类(Book.aidl)
package com.example.testproj.aidl;
parcelable Book;
接口类(AidlTestInterface.aidl)
// AidlTestInterface.aidl
package com.example.testproj.aidl;
// Declare any non-default types here with import statements
//此处注意,需要手动导入用到的实体类包。
import com.example.testproj.aidl.Book;
interface AidlTestInterface {
/**
* 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);
void addBook(in Book book);
List<Book> getBookList();
}
binder解析
如果使用aidl 编写了一个接口,那么as自动就会在app.build.generated.source.aidl 下面生成一个同文件名的java文件。所以我们就先来看下这个类
aidl自动生成的类
概况
public interface AidlTestInterface extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.testproj.aidl.AidlTestInterface{...}
/**
* 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);
public void addBook(com.example.testproj.aidl.Book book) throws android.os.RemoteException;
public java.util.List<com.example.testproj.aidl.Book> getBookList() throws android.os.RemoteException;
public interface IInterface
{
/**
* Retrieve the Binder object associated with this interface.
* You must use this instead of a plain cast, so that proxy objects
* can return the correct result.
*/
public IBinder asBinder();
}
这里代码应该是比较清晰简单的。AidlTestInterface 继承了系统的IInterface,然后定义了我们在aidl中定义中的两个方法。 最后就是定义了一个静态Binder内部类,实现了自己这个接口。
内部类
所以接下来,我们仔细看下这个内部类
public static abstract class Stub extends android.os.Binder implements com.example.testproj.aidl.AidlTestInterface {
//一般为binder的类名,用来唯一确认这个binder
private static final java.lang.String DESCRIPTOR = "com.example.testproj.aidl.AidlTestInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.testproj.aidl.AidlTestInterface interface,
* generating a proxy if needed.
* 将服务端的binder对象转换成客户端所需的aidl接口类型的对象
*/
public static com.example.testproj.aidl.AidlTestInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.testproj.aidl.AidlTestInterface))) {
//如果在相同进程中查找到这个aidl对应的对象,则直接返回。这里对应的就是
//未产生多进程通讯的场景。
return ((com.example.testproj.aidl.AidlTestInterface) iin);
}
//如果在本进程中没有找到对应的对象,则返回系统封装后的stub.proxy对象
return new com.example.testproj.aidl.AidlTestInterface.Stub.Proxy(obj);
}
/**
*返回当前binder对象
**/
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
*运行在服务端binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交给此方法处理
**/
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
//根据code确定客户端请求的目标方法是什么,如果这个方法返回false则客户端调用失败
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.testproj.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.testproj.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
//写入客户调用方法后的返回值
reply.writeNoException();
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.testproj.aidl.Book> _result = this.getBookList();
reply.writeNoException();
//写入客户调用方法后的返回值
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.testproj.aidl.AidlTestInterface {
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.
* 这个方法运行在客户端
*/// void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
// double aDouble, String aString);
@Override
public void addBook(com.example.testproj.aidl.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();//创建输入型Parcel 对象
android.os.Parcel _reply = android.os.Parcel.obtain();//创建输出型Parcel对象
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
//将参数写入输入型Parcel对象
_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();
}
}
@Override
public java.util.List<com.example.testproj.aidl.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();//创建输入型Parcel 对象
android.os.Parcel _reply = android.os.Parcel.obtain();//创建输出型Parcel对象
java.util.List<com.example.testproj.aidl.Book> _result;//创建返回值对象
try {
_data.writeInterfaceToken(DESCRIPTOR);
//发起远程请求,此处线程会挂起,直到返回内容
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
//取出返回结果
_reply.readException();
//将输出型Parcel对象的结果转化成需要的结果,并返回
_result = _reply.createTypedArrayList(com.example.testproj.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
流程图
注意事项
- AIDL只是生成接口的一种工具,如果不使用AIDL,我们手动去写这个接口,也是可行的。
- Binder提供了死亡绑定(linkToDeath,unlinkToDeath),可以在远程服务由于某种原因挂了,可以手动重启。