Android知识总结
一、Binder通信实现
1.1、model类
public class Person implements Parcelable {
private String name;
private int grade;
public Person(String name, int grade) {
this.name = name;
this.grade = grade;
}
protected Person(Parcel in) {
this.name = in.readString();
this.grade = in.readInt();
}
public static final Creator CREATOR = new Creator() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(grade);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
1.2、接口类
public interface IPersonManager extends IInterface {
void addPerson(Person person) throws RemoteException;
List getPersonList() throws RemoteException;
}
1.3、Proxy 类
Proxy 用于客户端的实现
public class Proxy implements IPersonManager {
//IPersonManager 的描述符
private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";
private IBinder mRemote;
public Proxy(IBinder remote) {
mRemote = remote;
}
@Override
public void addPerson(Person person) throws RemoteException {
//用于client向service中写入数据,打包成data
Parcel data = Parcel.obtain();
//用于client从service中读取数据,打包成reply
Parcel reply = Parcel.obtain();
try {
//检测
data.writeInterfaceToken(DESCRIPTOR);
if ((person != null)) {
//不为空时写入标识符1,用来service判定是否为空数据,从而序列化数据
data.writeInt(1);
//把person写入到 Parcel 中,就是序列化
person.writeToParcel(data, 0);
} else {
//标识符为0时,为空数据
data.writeInt(0);
}
Log.e("leo", "Proxy,addPerson: " + Thread.currentThread());
//用 transact 向 service 发出命令,用于跨进程,client 挂起(同步的情况)
mRemote.transact(Stub.TRANSACTION_addPerson, data, reply, 0);
reply.readException();
} finally {
reply.recycle();
data.recycle();
}
}
@Override
public List getPersonList() throws RemoteException {
//用于向service中写入数据
Parcel data = Parcel.obtain();
//用于client从service中读取数据
Parcel reply = Parcel.obtain();
List result;
try {
//检测
data.writeInterfaceToken(DESCRIPTOR);
//用 transact 向 service 发出命令,用于跨进程,client 挂起
mRemote.transact(Stub.TRANSACTION_getPersonList, data, reply, 0);
reply.readException();
//获取数据,从service中获取
result = reply.createTypedArrayList(Person.CREATOR);
} finally {
reply.recycle();
data.recycle();
}
return result;
}
@Override
public IBinder asBinder() {
return mRemote;
}
}
- 主要在三件事
- 1、打包两个 Parcel 数据
- 2、检测
- 3、transact 跨进程通信,并挂起
1.4、Stub 类
Stub 用于服务端的实现,必须继承 Binder
public abstract class Stub extends Binder implements IPersonManager {
private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";
//向binder中注入描述符
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 判断是同一个进程还是跨进程
*
* @param binder
* @return
*/
public static IPersonManager asInterface(IBinder binder) {
if ((binder == null)) {
return null;
}
//如果是跨进程返回为 null
IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
//同一个进程
if ((iin != null) && (iin instanceof IPersonManager)) {
return (IPersonManager) iin;
}
//跨进程
return new Proxy(binder);
}
@Override
public IBinder asBinder() {
return this;
}
/**
* 接收client发出的命令
*
* @param code 标识符
* @param data
* @param reply
* @param flags
* @return
* @throws RemoteException
*/
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION:
//
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_addPerson:
Log.e("leo", "Stub,TRANSACTION_addPerson: " + Thread.currentThread());
//执行这个描述符的服务
data.enforceInterface(DESCRIPTOR);
Person arg0 = null;
//不为0时写于数据
if ((0 != data.readInt())) {
//从Parcel中读取数据,就是反序列化
arg0 = Person.CREATOR.createFromParcel(data);
}
this.addPerson(arg0);
reply.writeNoException();
return true;
case TRANSACTION_getPersonList:
data.enforceInterface(DESCRIPTOR);
//this 指的是 RemoteService 服务
List result = this.getPersonList();
reply.writeNoException();
//向client返回结果
reply.writeTypedList(result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
//client 和 service 之间的标识
static final int TRANSACTION_addPerson = IBinder.FIRST_CALL_TRANSACTION;
static final int TRANSACTION_getPersonList = IBinder.FIRST_CALL_TRANSACTION + 1;
}
- asInterface 主要做的事情
- 1、返回 IInterface == null,表示跨进程。返回 Proxy(binder)
- 2、返回 IInterface != null,表示同进程,直接返。
- onTransact
- 1、根据 code 判断 clien向service端调用的方法
- 2、this.xxx 调用我们创建 Service 里面 stub 里的方法
- 3、通过 reply 向 Client 发送信息
1.5、Service 端
public class RemoteService extends Service {
private ArrayList persons;
@Nullable
@Override
public IBinder onBind(Intent intent) {
persons = new ArrayList<>();
Log.e("LeoAidlService", "success onBind");
return iBinder;
}
private IBinder iBinder = new Stub() {
@Override
public void addPerson(Person person) throws RemoteException {
persons.add(person);
}
@Override
public List getPersonList() throws RemoteException {
return persons;
}
};
}
1.6、client 实现类
public class ClientActivity extends AppCompatActivity {
private IPersonManager iPersonManager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, RemoteService.class);
intent.setAction("com.enjoy.binder");
bindService(intent, connection, Context.BIND_AUTO_CREATE);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Log.e("leo", "------------onClick:" + Thread.currentThread());
iPersonManager.addPerson(new Person("leo", 3));
List persons = iPersonManager.getPersonList();
Log.e("leo", persons.toString() + "," + Thread.currentThread());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("leo", "onServiceConnected: success");
iPersonManager = Stub.asInterface(service);// 返回 proxy,即 Client
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("leo", "onServiceDisconnected: success");
iPersonManager = null;
}
};
}
1.7、AndroidManifest.xml
二、AIDL 实现
2.1、支持的数据类型
- 1、Java 的基本数据类型
- 2、List 和 Map
1)、元素必须是 AIDL 支持的数据类型
2)、Server 端具体的类里则必须是 ArrayList 或者 HashMap - 3、其他 AIDL 生成的接口
- 4、实现 Parcelable 的实体
public class Person implements Parcelable {
private String name;
public Person(String name) {
this.name = name;
}
protected Person(Parcel in) {
name = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
}
2.2、AIDL 编写
AIDL 的编写主要为以下三部分:
- 1、创建 AIDL
1)、创建要操作的实体类,实现 Parcelable 接口,以便序列化/反序列化
2)、新建 aidl 文件夹,在其中创建接口 aidl 文件以及实体类的映射 aidl 文件
3)、Make project ,生成 Binder 的 Java 文件
// Person.aidl 实体类的映射 aidl 文件
package net.sxkeji.shixinandroiddemo2.bean;
//还要和声明的实体类在一个包里
parcelable Person;
// IMyAidl.aidl 接口 aidl 文件
package net.sxkeji.shixinandroiddemo2;
// Declare any non-default types here with import statements
import net.sxkeji.shixinandroiddemo2.bean.Person;
interface IMyAidl {
/**
* 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出)
*/
void addPerson(in Person person);
List getPersonList();
}
- 2、服务端
1)、创建 Service,在其中创建上面生成的 Binder 对象实例,实现接口定义的方法
2)、在 onBind() 中返回
public class PersonService extends Service {
private static final String TAG = "PersonService";
private CopyOnWriteArrayList mPerson;
private Binder mBinder = new IPersonService.Stub() {
@Override
public List getPersonList() throws RemoteException {
return mPerson;
}
@Override
public void addPerson(Person person) throws RemoteException {
mPerson.add(person);
}
};
@Override
public void onCreate() {
super.onCreate();
init();
}
private void init() {
mPerson = new CopyOnWriteArrayList<>();
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
- 3、客户端
1)、实现 ServiceConnection 接口,在其中拿到 AIDL 类
2)、bindService()
3)、调用 AIDL 类中定义好的操作请求
private IPersonService mPersonService;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mPersonService = IPersonService.Stub.asInterface(service);
if (mPersonService == null) {
Log.i(TAG, "mPersonService == null");
return;
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, PersonService.class);
intent.setPackage(PKG_NAME);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
三、Messenger 实现 AIDL
3.1、简介
Messenger它是一种轻量级的IPC 方法,我们使用起来也是非常的简单。他是使用Handler对AIDL进行了一次封装,一次只能处理一个请求。并且Messenger在发送Message的时候不能使用他的obj字段,我们可以用bundle来代替。最后还有一点就是Messenger只是在客户端与服务端跨进程的传递数据,而不能够去访问服务端的方法。
Messenger的使用步骤:
其实对于Messenger用起来是非常简单的,那么我们首先来看一下这个Messenger的使用步骤:
1. 在服务端我们实现一个 Handler,接收来自客户端的每个调用的回调
2. 这个Handler 用于创建 Messenger 对象(也就是对 Handler 的引用)
3. 用Messenger 创建一个 IBinder,服务端通过 onBind() 使其返回客户端
4. 客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务端
5. 服务端在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message
3.2、service端
public class HandlerService extends Service {
public static final int MESSAGE_TAG_1 = 1;
public static final int MESSAGE_TAG_2 = MESSAGE_TAG_1 + 1;
public static final int MESSAGE_TAG_3 = MESSAGE_TAG_2 + 1;
private Messenger serviceMessage = new Messenger(new BinderHandler());
public HandlerService() {
}
@Override
public IBinder onBind(Intent intent) {
return serviceMessage.getBinder();
}
private class BinderHandler extends Handler{
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Bundle data = msg.getData();
if(null == data){
return;
}
switch (msg.what){
case MESSAGE_TAG_1:
String message = data.getString("message");
Toast.makeText(HandlerService.this, message, Toast.LENGTH_LONG).show();
break;
case MESSAGE_TAG_2:
String str = data.getString("data");
Toast.makeText(HandlerService.this, str, Toast.LENGTH_LONG).show();
Message toClient = Message.obtain();
toClient.what = MESSAGE_TAG_3;
toClient.arg1 = 11111;
try {
//向客户端发送消息
msg.replyTo.send(toClient);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
}
}
3.3、client端
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Intent intent = new Intent(this, HandlerService.class);
intent.setAction("com.example.myapplication.service");
bindService(intent, connection, Context.BIND_AUTO_CREATE);
findViewById(R.id.click_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message message = Message.obtain();
message.what = HandlerService.MESSAGE_TAG_2;
Bundle bundle = new Bundle();
bundle.putString("data", "发送消息");
message.setData(bundle);
message.replyTo = clientMessenger;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private Messenger messenger = null;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message message = Message.obtain();
message.what = HandlerService.MESSAGE_TAG_1;
Bundle bundle = new Bundle();
bundle.putString("message", "建立连接");
message.setData(bundle);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
messenger = null;
}
};
//接受客户端消息
private Messenger clientMessenger = new Messenger(new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == HandlerService.MESSAGE_TAG_3) {
Toast.makeText(MainActivity.this, msg.arg1 + "", Toast.LENGTH_LONG).show();
}
}
});
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
}
客户端绑定服务端,获取远程Messenger的binder对象。调用Messenger的send函数,就可以吧Message发送至服务端的Handler。
同时,如果需要服务端回调客户端(往客户端的Handler发消息),则可以在send的Message中设置replyTo,服务端就可以往客户端发送消息了。
Messenger与 AIDL 比较:
- 当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。
- 对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口
3.4、发送流程
调用Messenger#send
方法发送消息:
private final IMessenger mTarget;
//构造函数
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
在IMessenger.aidl #send
的方法:
oneway interface IMessenger {
void send(in Message msg);
}
Handler.getIMessenger()返回的是一个IMessenger的binder对象,它的send方法将会调用Handler的sendMessage方法。
源码