学习和使用Android Service也有一段时间了,今天有点总结和记录下个人感悟的想法。
首先,我们要明白,Binder只是Android中众多IPC方式中的一种。只不过相对于其它IPC方式,在Android中,Binder更为灵活和方便而已。
其次,Binder通信和业务之间的关系:
1> Binder 是通信机制
2> 业务只是基于Binder进行通信,当然也可以使用别的IPC方式通信
说白了,Binder只是一种传递数据的方式,是为业务服务的。而Android帮我们把Binder的这种通信机制和我们的业务巧妙地封装融合在一起,使我们在实际应用过程中不用花费大量的精力和时间在IPC通信上,而是更加专注在业务逻辑的实现上。
AIDL 文件:
package com.test.demo;
interface ITestService {
int Add();
}
Build Java工程会根据ITestService.aidl文件生成ITestService.java文件:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\src\\com\\test\\demo\\ITestService.aidl
*/
package com.test.demo;
public interface ITestService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.test.demo.ITestService
{
private static final java.lang.String DESCRIPTOR = "com.test.demo.ITestService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.test.demo.ITestService interface,
* generating a proxy if needed.
*/
public static com.test.demo.ITestService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.test.demo.ITestService))) {
return ((com.test.demo.ITestService)iin);
}
return new com.test.demo.ITestService.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_Add:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.Add();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.test.demo.ITestService
{
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 int Add() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_Add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_Add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int Add() throws android.os.RemoteException;
}
ITestService.java 中定义了ITestService接口和子类Stub以及Stub的子类Proxy
Stub类是一个抽象类,从Binder和ITestService接口派生而来,它是给Server端即Service使用的。我们要在Service中定义一个Stub类实例,并且实现这样一个Stub类实例中对应的ITestService的接口函数。
Proxy类也是从ITestService派生而来,它是给Client端用的。它其实就是Client访问Service的一个代理,它内部有一个BpBinder,通过它可以和Service里的BBinder进行通信。
Client访问Proxy感觉就像Client直接访问Service一样。
很好奇为什么Stub中的asInterface为什么不是直接返回Proxy对象?竟然有可能返回一个Stub对象?
/**
* Cast an IBinder object into an com.test.demo.ITestService interface,
* generating a proxy if needed.
*/
public static com.test.demo.ITestService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.test.demo.ITestService))) {
return ((com.test.demo.ITestService)iin);
}
return new com.test.demo.ITestService.Stub.Proxy(obj);
}
Binder类中的queryLocalInterface和attachInterface方法:
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
而我们从Stub的构造函数中可以看到,owner就是Stub对象的this指针,即当前的Stub对象自己
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
所以,asInterface从一个IBinder对象可以转换成一个Proxy或是一个Stub对象。Proxy对象,很好理解,即Proxy里是封装了BpBinder, 通过BpBinder和server端的BBinder进行通信。 那Stub对象呢,什么时候会返回一个Stub对象呢? 我个人的理解是当service是一个本地service的时候,只有这种情况的时候拿到IBinder对象后是不需要Proxy进行跨进程通信,而直接可以使用Server端实现的Stub对象来访问service的方法(个人猜测,未经证实。后面有时间可以去测试下)。