Android——AIDL基础实现demo以及原理探究

来源:互联网 发布:杜兰特对位科比数据 编辑:程序博客网 时间:2024/06/15 17:46
最近有一段时间没写博客了,打算最近趁着有时间补补,本文是总结的AIDL的基本使用和原理。
分为两个部分:一是简单的上手demo,二是对代码逻辑进行分析。

一:简单的AIDL小Demo:
服务端:
1.新建服务端工程AIDLserver,新建AIDL文件:

2.打开该文件,编写一个测试方法:

3.点击build-rebuild进行编译,可以看到生成的java类文件,在最后一行可以看到自己刚才写的测试方法input():

4.编写服务端的服务类:

这里要注意一定要返回Ibinder实例。
5.在Manifest里配置该服务,在Activity中启动服务并运行程序:

启动服务



客户端:
1.新建客户端工程AIDLClient,新建一个module工程mylibrary:

2.把之前服务端的aidl文件夹复制到客户端相同位置,并rebuild客户端:

3.在MainActivity中绑定服务端的TESTServer服务,并通过ServiceConnection进行消息回调,在其的onServiceConnected方法中得到IMyAidlInterface的实例。
4.之后创建一个按钮的点击方法,在其中直接调用IMyAidlInterface实例对象发出客户端的信息并直接获得服务端的回调结果。
(3、4完整代码如下):
public class MainActivity extends AppCompatActivity {
    Button btn_test_aidl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn_test_aidl = (Button) findViewById(R.id.btn_test_aidl);
        //绑定服务
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.example.aidlserver""com.example.aidlserver.MyService"));
        bindService(intentconnBIND_AUTO_CREATE);

        btn_test_aidl.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    String rep = iMyAidlInterface.input("客户端发出的信息");
                    Log.i("nangua""从服务端调用成功的结果:" + rep);
               catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    IMyAidlInterface iMyAidlInterface;

    /**
     * 服务回调方法
     */
    private ServiceConnection conn new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName nameIBinder service) {
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iMyAidlInterface null;
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //解绑服务,回收资源
        unbindService(conn);
    }

}

最后,点击客户端测试按钮,查看双端显示的Log:



二.底层实现原理:

围绕着IMyAidlInterface的代码(方便查找):
/* * This file is auto-generated.  DO NOT MODIFY. * Original file: E:\\Android-workspace\\AIDLsample\\AIDLClient\\app\\src\\main\\aidl\\com\\example\\aidlserver\\IMyAidlInterface.aidl */package com.example.aidlserver;// Declare any non-default types here with import statementspublic interface IMyAidlInterface extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.example.aidlserver.IMyAidlInterface{private static final java.lang.String DESCRIPTOR = "com.example.aidlserver.IMyAidlInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.example.aidlserver.IMyAidlInterface interface, * generating a proxy if needed. */public static com.example.aidlserver.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.example.aidlserver.IMyAidlInterface))) {return ((com.example.aidlserver.IMyAidlInterface)iin);}return new com.example.aidlserver.IMyAidlInterface.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_basicTypes:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();long _arg1;_arg1 = data.readLong();boolean _arg2;_arg2 = (0!=data.readInt());float _arg3;_arg3 = data.readFloat();double _arg4;_arg4 = data.readDouble();java.lang.String _arg5;_arg5 = data.readString();this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);reply.writeNoException();return true;}case TRANSACTION_input:{data.enforceInterface(DESCRIPTOR);java.lang.String _arg0;_arg0 = data.readString();java.lang.String _result = this.input(_arg0);reply.writeNoException();reply.writeString(_result);return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.example.aidlserver.IMyAidlInterface{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;}/**    * 自动生成的方法     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.writeInt(anInt);_data.writeLong(aLong);_data.writeInt(((aBoolean)?(1):(0)));_data.writeFloat(aFloat);_data.writeDouble(aDouble);_data.writeString(aString);mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}@Override public java.lang.String input(java.lang.String str) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeString(str);mRemote.transact(Stub.TRANSACTION_input, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}}static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_input = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);}/**    * 自动生成的方法     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;public java.lang.String input(java.lang.String str) throws android.os.RemoteException;}


从客户端开始,一步步说:
1.首先在onCreate方法中,绑定了服务端的TestServer服务:
//绑定服务        Log.d("nangua","客户端onCreate中绑定服务");        Intent intent = new Intent();        intent.setComponent(new ComponentName("com.example.aidlserver", "com.example.aidlserver.TestService"));        bindService(intent, conn, BIND_AUTO_CREATE);
其中我们传入的ServiceConnection为:
    /**     * 服务回调方法     */    private ServiceConnection conn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.d("nangua","客户端回调获得iMyAidlInterface实例");            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {            iMyAidlInterface = null;        }    };
在onServiceConnected中,我们调用了IMyAidlInterface实例的Stub内部类的asInterface方法,我们走进该方法:

public static com.example.aidlserver.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.example.aidlserver.IMyAidlInterface))) {return ((com.example.aidlserver.IMyAidlInterface)iin);}return new com.example.aidlserver.IMyAidlInterface.Stub.Proxy(obj);}
可以看到最后一行返回结果是调用了Stub内部类的代理内部类Proxy的构造方法,该方法为:
private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}
可以看到讲传入的远程服务类的IBinder实例保存到了本地,变量名为mRemote(意思是拿到的远程实例).
到此为止,我们可以知道客户端的IMyAidlInterface实例iMyAidlInterface就是该代理类实例mRemote。
然后在我们的点击方法中:
  btn_test_aidl.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                try {                    Log.d("nangua","点击了");                    String rep = iMyAidlInterface.input("客户端发出的信息");                    Log.d("nangua", "从服务端调用成功的结果:" + rep);                } catch (Exception e) {                    e.printStackTrace();                }            }        });
是调用了该实例的input方法,所以现在看到Proxy代理类的input方法:
@Override public java.lang.String input(java.lang.String str) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeString(str);mRemote.transact(Stub.TRANSACTION_input, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}
可以看到其中关键的一句:
mRemote.transact(Stub.TRANSACTION_input, _data, _reply, 0);
调用了mRemote实例的transact方法,其中TRANSACTION_input是标志值。
该方法会调用服务端的onTransact方法!
所以此时我们看到服务端IMyAidlInterface实例的代理类Proxy的onTranscat方法:
@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_basicTypes:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();long _arg1;_arg1 = data.readLong();boolean _arg2;_arg2 = (0!=data.readInt());float _arg3;_arg3 = data.readFloat();double _arg4;_arg4 = data.readDouble();java.lang.String _arg5;_arg5 = data.readString();this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);reply.writeNoException();return true;}case TRANSACTION_input:{data.enforceInterface(DESCRIPTOR);java.lang.String _arg0;_arg0 = data.readString();java.lang.String _result = this.input(_arg0);reply.writeNoException();reply.writeString(_result);return true;}}return super.onTransact(code, data, reply, flags);}
可以看到在case TRANSACTION_input:的情况下,
会得到客户端传来的数据:
java.lang.String _arg0;_arg0 = data.readString();
然后执行服务端的input方法:
java.lang.String _result = this.input(_arg0);
最后将数据保存:
reply.writeNoException();reply.writeString(_result);
并返回数据:
return super.onTransact(code, data, reply, flags);
onTransact方法走的是底层代码,通过这个方法的实现,可以将服务端的数据回传给客户端。
此时,客户端的执行方法终于收到了回传的参数:
                    String rep = iMyAidlInterface.input("客户端发出的信息");
到此,全过程结束。

总结:
可以看到整个数据交互过程,就是客户端通过绑定服务,得到服务端的Aidl实例mRemote,并通过调用该实例的input方法,并在input方法中最终调用进程间通信的底层方法onTransact,实现数据从客户端到服务端,再到客户端的整个回调。过程虽然比较复杂,但是思路是连贯的。












原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 做完蹲起大腿疼怎么办 练腿之后腿疼怎么办 深蹲做完后腿疼怎么办 做完上下蹲腿疼怎么办 钓鱼子线长了怎么办 烤箱烤红薯没有锡纸怎么办 烤箱烤羊肉串滴油怎么办 黄金虎嘴脱臼了怎么办 孕妇吃了马头鱼怎么办 慈鲷鱼生完小鱼怎么办 买的烤鱼片刺多怎么办 鸡蛋不太新鲜了怎么办 麻雀从巢里掉下来怎么办 小鱼生了鱼蛋怎么办 吃了没熟透的鱼怎么办 吃了变质的虾怎么办 吃了不新鲜的肉怎么办 吃不新鲜的虾怎么办 鸡胸肉不新鲜了怎么办 吃了不新鲜的鱼怎么办 生的猪肉有点臭怎么办? 猪肉馅不新鲜了怎么办 买的肉有点臭了怎么办 炸的东西不脆了怎么办 油炸东西回软了怎么办 吃石斑鱼蛋吐了怎么办 家里的烟筒堵了怎么办 脖子上长鸡皮肤怎么办 铁板烤蔬菜粘锅怎么办 残余尿量300ml怎么办 肌肉拉伤怎么办恢复快小腿 睡觉把背扭了怎么办 后背一侧扭筋了怎么办 背部的筋扭到了怎么办 跳绳跳得膝盖疼怎么办 跑步小腿变粗了怎么办 一蹲下膝盖就响怎么办 做深蹲时膝盖总是吱吱响怎么办 爬山爬的膝盖疼怎么办 膝盖一吹风就疼怎么办 走路太多膝盖腿疼怎么办