1.binder是什么
binder英文意思理解为胶水,它是实现IPC通讯的一种方式,是Android 系统中实现进程中通讯的主要方式。我们都知道Android 系统都是基于Linux架构的,为什么不能使用Linux中的进程通讯方式呢?我们都知道,Android系统和Linux系统不同的是,Android系统有很多应用需要管理,每一个应用都跑在属于自己的进程中,首先要考虑安全问题,如果使用像Linux系统中的内存共享,管道之类的实现进程中通讯的方式,那么每个应用以及系统之间的服务的安全得不到保证。而Socket这种方式实现的效率太低,只适合网络通讯。那么为了解决Android 系统的这种特有的需求,Android 系统架构师肯定会想,我可不可以做一个可以保证进程间通讯安全,又能像socket这样方便的东西呢?Binder机制就这么诞生了,在Android 系统中,Binder有一个特有的驱动程序,虽然它没有硬件设备,但它和其它硬件模块一样不可缺少,它类似于整个系统的路由器,它为系统中的每个服务都绑定了一个固定的Ip,如果你想要实现进程中通讯,比如你想要调取摄像头的服务,那么你只要指定摄像头的服务,然后将信息通过binder发给ManagerService,ManagerService帮你找到摄像头的服务,然后帮你的进程和摄像头服务的进程建立连接。当然,在你调用服务的时候,Android系统会审核这个进程是否有调用摄像头权限,这些审核机制应该在调用服务之前就已经完成,Binder只负责实现通讯。如此可以看出来,Binder就像胶水一样,把每个应用都通过它粘连起来。
2.如何实现Binder通讯,
Android 在使用Binder进行通讯的时候,定义了一套规则,俗称AIDL,全称Android Interface definition language,即Android接口定义语言,看名称就明白,如果你要使用这个东西,那么你必须按照它的规则来实现。下面是一个实现的例子。简单实现了一个图书管理的客户端和服务端的通讯,在一个服务进程中管理书籍,而在另外一个进程中去获得这些书籍的信息。定义一个Book类,固定实现Pacerlable接口,我们都知道Pacerlable是Andriod实现序列化的一个接口,在AIDL中,有特定的几种类型可以传输,比如Int,String,Float之类的,除此之外,如果你想要传一个别的对象,那么必须要实现Pacerlable方法。如下面的代码
package com.example.weizhang.myaidltest;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by Administrator on 2017/12/3 0003.
*/
public class Book implements Parcelable {
private String name;
private int price;
public Book(String name, int price) {
this.name = name;
this.price = price;
}
public Book() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeInt(this.price);
}
protected Book(Parcel in) {
this.name = in.readString();
this.price = in.readInt();
}
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];
}
};
}
实现完这个以后,接下来要在项目中建立一个aidl的文件夹,文件夹位置和java同级。在AS中可以点击app,然后选择aidl,项目会自动生成一个aidl文件夹
,然后在这个文件夹中建立以下两个文件。一个是Book类的申明,一个是实际的接口,其实第一个申明是为了第二个接口调用做的申明。
// IBookManerger.aidl
package com.example.weizhang.myaidltest;
// Declare any non-default types here with import statements
parcelable Book;
// IBookManerger.aidl
package com.example.weizhang.myaidltest;
import com.example.weizhang.myaidltest.Book;
interface IBookManerger {
//所有的返回值前都不需要加任何东西,不管是什么数据类型
List<Book> getBooks();
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
void addBook(in Book book);
}
点击Rebuild,系统中的脚本会为我们在gen目录下的生成一个java文件,名称即为我们在aidl中命名的文件
我们来看一下这个类,在看这个类之前,先想一下这个类应该要实现什么功能,首先,要想实现进程中通讯,我们要把自己的一些信息先注册给serviceManerger,然后客户端才能调用到这个接口,而之前已经说过了,Android中实现进程中通讯,使用的是BInder,那么为了实现注册,我们必须要使用Binder。
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\AndroidDemo\\app\\src\\main\\aidl\\com\\example\\weizhang\\myaidltest\\IBookManerger.aidl
*/
package com.example.weizhang.myaidltest;
public interface IBookManerger extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.example.weizhang.myaidltest.IBookManerger {
private static final java.lang.String DESCRIPTOR = "com.example.weizhang.myaidltest.IBookManerger";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.weizhang.myaidltest.IBookManerger interface,
* generating a proxy if needed.
*/
public static com.example.weizhang.myaidltest.IBookManerger asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.weizhang.myaidltest.IBookManerger))) {
return ((com.example.weizhang.myaidltest.IBookManerger) iin);
}
return new com.example.weizhang.myaidltest.IBookManerger.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@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_getBooks: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.weizhang.myaidltest.Book> _result = this.getBooks();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.weizhang.myaidltest.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.weizhang.myaidltest.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.example.weizhang.myaidltest.IBookManerger {
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.example.weizhang.myaidltest.Book> getBooks() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.weizhang.myaidltest.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.weizhang.myaidltest.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
@Override
public void addBook(com.example.weizhang.myaidltest.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();
}
}
}
static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
//所有的返回值前都不需要加任何东西,不管是什么数据类型
public java.util.List<com.example.weizhang.myaidltest.Book> getBooks() throws android.os.RemoteException;
//传参时除了Java基本类型以及String,CharSequence之外的类型
//都需要在前面加上定向tag,具体加什么量需而定
public void addBook(com.example.weizhang.myaidltest.Book book) throws android.os.RemoteException;
}
可以看到,manerger里面有个子类stub,stub中又有一个私有的子类proxy。要想理解这个结构,我们必须要明白设计模式中的一个模式,代理模式。stub和Proxy都实现了同一个接口,proxy是stub的代理。我们可以看到,Proxy持有了一个Binder对象,即
private android.os.IBinder mRemote;
这个对象包含了各种信息,通过将这个Binder发送给ServiceManerger就实现了服务的注册。我们来看一下Service中是如何将Binder发送出去的。
可以看到,其实就是创建一个继承stub的对象,然后在Onbind方法中,将这个对象抛出去,那么在客户端就可以拿到这个binder,然后调用这个接口的函数了。package com.example.weizhang.myaidltest; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.support.annotation.Nullable; import android.util.Log; import java.util.ArrayList; import java.util.List; /** * 服务端的AIDLService.java * <p/> */ public class AIDLService extends Service { public final String TAG = this.getClass().getSimpleName(); //包含Book对象的list private List<Book> mBooks = new ArrayList<>(); //由AIDL文件生成的IBookManerger private final IBookManerger.Stub mIBookManerger = new IBookManerger.Stub() { @Override public List<Book> getBooks() throws RemoteException { synchronized (this) { Log.e(TAG, "invoking getBooks() method , now the list is : " + mBooks.toString()); if (mBooks != null) { return mBooks; } return new ArrayList<>(); } } @Override public void addBook(Book book) throws RemoteException { synchronized (this) { if (mBooks == null) { mBooks = new ArrayList<>(); } if (book == null) { Log.e(TAG, "Book is null in In"); book = new Book(); } //尝试修改book的参数,主要是为了观察其到客户端的反馈 book.setPrice(2333); if (!mBooks.contains(book)) { mBooks.add(book); } //打印mBooks列表,观察客户端传过来的值 Log.e(TAG, "invoking addBooks() method , now the list is : " + mBooks.toString()); } } }; @Override public void onCreate() { super.onCreate(); Book book = new Book(); book.setName("Android开发艺术探索"); book.setPrice(28); mBooks.add(book); } @Nullable @Override public IBinder onBind(Intent intent) { Log.e(getClass().getSimpleName(), String.format("on bind,intent = %s", intent.toString())); return mIBookManerger; } }