进程间通信学习系列(二)——简单了解Binder机制
程序员文章站
2024-03-24 08:19:58
...
进程间通信学习系列(一)——IPC简介
Binder机制太复杂了,本文只是简单的对Binder进行了解。
在Android中Binder是一个类,实现了IBinder接口,在Binder机制中还有两个重要角色Binder驱动(在内核中)和ServiceManager,这两部分Android平台已经实现,我们不必关心,当然有兴趣的童鞋可以研究下。本文主要学习了解应用层的Client和Service相关的Binder知识。
Messenge,ContentProvider等底层实现都是AIDL,所以以AIDL的简单实现来学习Binder机制。
需求:图书管理系统中,1.需要查询图书列表;2.添加新书到图书库中。
先看一下目录结构:
首先新建一个Book类,并实现Parcelable序列化接口(Android Studio一键生成序列化代码插件),如下:
public class Book implements Parcelable {
private double price;
private long bookId;
private String bookName;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeDouble(this.price);
dest.writeLong(this.bookId);
dest.writeString(this.bookName);
}
public Book() {
}
protected Book(Parcel in) {
this.price = in.readDouble();
this.bookId = in.readLong();
this.bookName = in.readString();
}
public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
新建IBookManager.aidl文件,生命两个接口:
package anyan.com.ipcdemo.aboutaidl;
//注意导入Book类(手动导入)
import anyan.com.ipcdemo.aboutaidl.Book;
interface IBookManager {
List<Book> getBookList();//查询图书列表
void addBook(in Book book);//添加新图书
}
因为在IBookManager.aidl文件中使用了非基本数据类型,所以Book类不仅要实现序列化接口,还要新建一个Book.aidl文件(至于为什么,我也不知道),注意这个Book.aidl文件的全路径包名要与Book.java的全路径包名一致,否则编译会报错。内容如下:
package anyan.com.ipcdemo.aboutaidl;
parcelable Book;
Rebuild project成功后再app/build/generated/source/aidl/debug/包名 目录下回生成一个IBookManager.java文件,这是AS帮我们自动生成的,这里使用了代理模式(可简单了解一下,Java设计模式-代理模式实现及原理)主要分析这里的代码:包含两个接口getBookList()和addBook(),可以看到这两个接口就是我们在IBookManager.aidl文件中所声明的。一个内部类Stub,继承Binder实现IBookManager接口。Stub类里面还有一个内部类Proxy也实现了IBookManager接口,这个就是Stub类(也就是Binder)的代理类。
public interface IBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements anyan.com.ipcdemo.aboutaidl.IBookManager {
//Binder的唯一标识,一般用类名表示
private static final java.lang.String DESCRIPTOR = "anyan.com.ipcdemo.aboutaidl.IBookManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an anyan.com.ipcdemo.aboutaidl.IBookManager interface,
* generating a proxy if needed.
* 将IBinder对象转换成IBookManager接口并返回
* 这种转换区分进程,如果是在同一进程,直接返回服务端的Stub对象;
* 如果不在同一进程,则返回代理对象Stub.Proxy;
*/
public static anyan.com.ipcdemo.aboutaidl.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof anyan.com.ipcdemo.aboutaidl.IBookManager))) {
return ((anyan.com.ipcdemo.aboutaidl.IBookManager) iin);
}
return new anyan.com.ipcdemo.aboutaidl.IBookManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
/**
* 该方法在服务端的Binder线程池中执行,注意采用同步方法
* @param code 确定客户端请求的目标方法是哪个
* @param data 目标方法所需参数数据
* @param reply 目标方法返回数据
* @param flags
* @return
* @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<anyan.com.ipcdemo.aboutaidl.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
anyan.com.ipcdemo.aboutaidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = anyan.com.ipcdemo.aboutaidl.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 anyan.com.ipcdemo.aboutaidl.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;
}
/**
* 该方法在客户端执行,
* @return
* @throws android.os.RemoteException
*/
@Override
public java.util.List<anyan.com.ipcdemo.aboutaidl.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<anyan.com.ipcdemo.aboutaidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//调用远程请求,当前线程挂起,服务端OnTransact()方法会被调用,
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
//当前线程继续执行,取出结果
_reply.readException();
_result = _reply.createTypedArrayList(anyan.com.ipcdemo.aboutaidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(anyan.com.ipcdemo.aboutaidl.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();
}
}
}
//方法的id
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<anyan.com.ipcdemo.aboutaidl.Book> getBookList() throws android.os.RemoteException;
public void addBook(anyan.com.ipcdemo.aboutaidl.Book book) throws android.os.RemoteException;
}
如下图所示:
接着看具体怎么使用,创建一个BookManagerService类:
public class BookService extends Service {
public BookService() {
}
//支持并发读写
private CopyOnWriteArrayList<Book> bookList = new CopyOnWriteArrayList<>();
private IBookManager.Stub binder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return bookList;
}
@Override
public void addBook(Book book) throws RemoteException {
bookList.add(book);
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
在Activity中BindService:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private IBookManager iBookManager;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//用到了上面提到了转换方法asInterface,将IBinder转换为接口,
//同一进程直接返回Stub对象,不同进程返回Proxy代理类
iBookManager = IBookManager.Stub.asInterface(service);
try {
service.linkToDeath(deathRecipient, 0);
//拿到对象后就可以直接调用方法了
List<Book> bookList = iBookManager.getBookList();
Log.e(TAG, "onServiceConnected: " + bookList);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//死亡代理,binder死亡时会收到通知,回调binderDied方法
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (iBookManager == null)
return;
iBookManager.asBinder().unlinkToDeath(deathRecipient, 0);
iBookManager = null;
//重新绑定service
Intent intent = new Intent(MainActivity.this, BookService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
Intent intent = new Intent(this, BookService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
}
}
至此,简单的Binder机制分析完了,看着可能有点懵,很正常,我是看了好几篇才只是简单的理解了。Fighting !!!