Android — Activity与Service交互之Binder总结

最近在复习Android跨进程调用,整理了一下自己对Binder的一些理解,希望能对大家也有所帮助,如有错误欢迎指正~
为了加深理解,希望看完后能自己操练验证一下,要不真的很容易眼高手低哦
ps:不想细看,可以只看里面的3张图片即可~ ^_^

好了,回归主题,我们现在写个AIDL文件:

#IController.aidl
// Declare any non-default types here with import statements
interface IController {
    void showMessage(String msg);
}

我们先来看一下默认生成文件的注释:

意思是说:如果不是默认类型,需要进行相应的import,类似java导包一样

那默认类型有哪些呢?
int、long、boolean、float、double、String、in/out/inout List
Parcelable的实现类、aidl接口类这个是需要进行import的


添加完AIDL文件后,我们编译一下,然后找到IController.java类,这个类是系统帮我们把AIDL文件转化为一个Java类,便于我们进行使用,当然我们自己也可以写~~
我们来看一下这个类的代码:

public interface IController extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.yukai.test.IController {
        private static final java.lang.String DESCRIPTOR = "com.example.yukai.test.IController";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.yukai.test.IController interface,
         * generating a proxy if needed.
         */
        public static com.example.yukai.test.IController asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.yukai.test.IController))) {
                return ((com.example.yukai.test.IController) iin);
            }
            return new com.example.yukai.test.IController.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_showMessage: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.showMessage(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.yukai.test.IController {
            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 void showMessage(java.lang.String msg) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(msg);
                    mRemote.transact(Stub.TRANSACTION_showMessage, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_showMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    public void showMessage(java.lang.String msg) throws android.os.RemoteException;
}

这是格式化之后的样子,我对这个类做了一个初步的结构图绘制如下:
aidl结构图1
可以比较明显的看到类的嵌套结构,一个接口类:IController,里面包含了接口方法(即我们声明的那个方法)和 一个Stub类:

为屏蔽客户调用远程主机上的对象,必须提供某种方式来模拟本地对象,这种本地对象称为存根(stub),存根负责接收本地方法调用,并将它们委派给各自的具体实现对象

我觉得上面这个解释还可以,基本表达了Stub的作用~


看完上面的图,觉得还是有点乱,既然是static class 静态内部类,那其实我们可以把里面的class抽离出来,作为一个新的文件,参考下图结构:
2
其中IController、Stub、Proxy类可以看成三个独立的类/接口
继承关系图也可以很清晰的看出来,那这三者是如何相互合作使用的呢?下面这个图可以很好的表达出具体的Activity与本地/远程Service交互逻辑和对应上面几个类的使用:
3

图注:
左面的Service是跟Activity处于同一个进程下的
右面的Service是跟Activity非同一个进程下的,可能是remote或其他
“所以测试的时候需要分别测这两种情况,有process:remote和什么都不写默认进程的。”

1.与当前进程的Service交互

在bind Service后,onServiceConnected会返回对应的binder对象,我们可以调试发现这个对象跟Service里面的binder对象其实是 同一个对象,因此我们可以直接转成我们Service的Binder,然后直接调用;当然如果用的是AIDL的方式,我们可以调用Stub的静态方法:asInterface,可以做相应的转化。
说到这里,我们还需要看一下这个asInterface方法实现,先只看一半:

public static com.test.IController asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.test.IController))) {
        return ((com.test.IController) iin);
    }
    --------other return-------
}

关键在这里:
queryLocalInterface,查看源码可以发现,里面判断的是参数的IBinder对象的描述符是否是DESCRIPTOR,如果是,就会返回IController这个owner对象,所以就可以进行相应的强转并返回。
那remote返回什么呢?那看一下第二条吧~

2.与remote进程的Service交互

我们来看一下上面省略的那行代码:

return new com.test.IController.Stub.Proxy(obj);

看到这里原来返回的是个Proxy对象,那个obj会是什么呢?通过调试发现类名是BinderProxy对象,这个类我们的SDK里看不到,但是我们能在源码里找到,发现这个类是也是继承IBinder类,这个类负责与底层binder进行传递数据,然后会调用远程的Stub.onTransact,进行真实的Service方法调用。参照图片可以更好的理解一下~

3. 对应的Service与Activity进行交互

我们可以通过RemoteCallbackList这个类进行相关注册并进行回调,这个实现起来像是Activity是服务端,Service是客户端,大家可以实现一下看看~ 发现Stub是在Activity里新建并传递给Service端,由Service进行相应回调。当然还可以通过其他方式,比如广播(LocalBroadcast)也是可以的~~

就先写到这,如果有不对的地方,欢迎指正,多谢~~


原文地址:http://blog.csdn.net/yk3372/article/details/53295704

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值