• Binder系列9—如何使用AIDL


    copy from: http://gityuan.com/2015/11/23/binder-aidl/

    自定义binder架构的 client/ server组件

    一、AIDL

    1.1 Server端

    RemoteService.java

    本例是为了演示进程间的通信机制,故需要将Service与Activity处于不同的进程,需要在AndroidManifest.xml中,把service配置成android:process=":remote",进程也可以命名成其他的。

    public class RemoteService extends Service {
        private static final String TAG = "BinderSimple";
    
        MyData mMyData;
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i(TAG, "[RemoteService] onCreate");
            initMyData();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            Log.i(TAG,"[RemoteService] onBind");
            return mBinder;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            Log.i(TAG, "[RemoteService] onUnbind");
            return super.onUnbind(intent);
        }
    
        @Override
        public void onDestroy() {
            Log.i(TAG, "[RemoteService] onDestroy");
            super.onDestroy();
        }
    
        /** * 实现IRemoteService.aidl中定义的方法 */
        private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
    
            @Override
            public int getPid() throws RemoteException {
                Log.i(TAG,"[RemoteService] getPid()="+android.os.Process.myPid());
                return android.os.Process.myPid();
            }
    
            @Override
            public MyData getMyData() throws RemoteException {
                Log.i(TAG,"[RemoteService] getMyData() "+ mMyData.toString());
                return mMyData;
            }
    
            /**此处可用于权限拦截**/
            @Override
            public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
                return super.onTransact(code, data, reply, flags);
            }
        };
    
        /** * 初始化MyData数据 **/
        private void initMyData() {
            mMyData = new MyData();
            mMyData.setData1(10);
            mMyData.setData2(20);
        }
    }
    

    1.2 Client端

    ClientActivity.java

    public class ClientActivity extends AppCompatActivity {
        private static final String TAG = "BinderSimple";
    
        private IRemoteService mRemoteService;
    
        private boolean mIsBound;
        private TextView mCallBackTv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.i(TAG, "[ClientActivity] onCreate");
    
            setContentView(R.layout.activity_main);
    
            mCallBackTv = (TextView) findViewById(R.id.tv_callback);
            mCallBackTv.setText(R.string.remote_service_unattached);
        }
    
        /**
         * 用语监控远程服务连接的状态
         */
        private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
    
                mRemoteService = IRemoteService.Stub.asInterface(service);
                String pidInfo = null;
                try {
                    MyData myData = mRemoteService.getMyData();
                    pidInfo = "pid="+ mRemoteService.getPid() +
                            ", data1 = "+ myData.getData1() +
                            ", data2="+ myData.getData2();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                Log.i(TAG, "[ClientActivity] onServiceConnected  "+pidInfo);
                mCallBackTv.setText(pidInfo);
                Toast.makeText(ClientActivity.this, R.string.remote_service_connected, Toast.LENGTH_SHORT).show();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.i(TAG, "[ClientActivity] onServiceDisconnected");
                mCallBackTv.setText(R.string.remote_service_disconnected);
                mRemoteService = null;
                Toast.makeText(ClientActivity.this, R.string.remote_service_disconnected, Toast.LENGTH_SHORT).show();
            }
        };
    
    
        public void clickHandler(View view){
            switch (view.getId()){
                case R.id.btn_bind:
                    bindRemoteService();
                    break;
    
                case R.id.btn_unbind:
                    unbindRemoteService();
                    break;
    
                case R.id.btn_kill:
                    killRemoteService();
                    break;
            }
        }
    
        /**
         * 绑定远程服务
         */
        private void bindRemoteService(){
            Log.i(TAG, "[ClientActivity] bindRemoteService");
            Intent intent = new Intent(ClientActivity.this, RemoteService.class);
            intent.setAction(IRemoteService.class.getName());
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    
            mIsBound = true;
            mCallBackTv.setText(R.string.binding);
        }
    
        /**
         * 解除绑定远程服务
         */
        private void unbindRemoteService(){
            if(!mIsBound){
                return;
            }
            Log.i(TAG, "[ClientActivity] unbindRemoteService ==>");
            unbindService(mConnection);
            mIsBound = false;
            mCallBackTv.setText(R.string.unbinding);
        }
    
        /**
         * 杀死远程服务
         */
        private void killRemoteService(){
            Log.i(TAG, "[ClientActivity] killRemoteService");
            try {
                android.os.Process.killProcess(mRemoteService.getPid());
                mCallBackTv.setText(R.string.kill_success);
            } catch (RemoteException e) {
                e.printStackTrace();
                Toast.makeText(ClientActivity.this, R.string.kill_failure, Toast.LENGTH_SHORT).show();
            }
        }
    }
    

    1.3 AIDL文件

    (1)IRemoteService.aidl 定义远程通信的接口方法

    interface IRemoteService {
        int getPid();
        MyData getMyData();
    }
    

    (2)MyData.aidl 定义远程通信的自定义数据

    parcelable MyData;
    

    1.4 Parcel数据

    MyData.java

    public class MyData implements Parcelable {
        private int data1;
        private int data2;
    
        public MyData(){
    
        }
    
        protected MyData(Parcel in) {
            readFromParcel(in);
        }
    
        public static final Creator<MyData> CREATOR = new Creator<MyData>() {
            @Override
            public MyData createFromParcel(Parcel in) {
                return new MyData(in);
            }
    
            @Override
            public MyData[] newArray(int size) {
                return new MyData[size];
            }
        };
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        /** 将数据写入到Parcel **/
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(data1);
            dest.writeInt(data2);
        }
    
        /** 从Parcel中读取数据 **/
        public void readFromParcel(Parcel in){
            data1 = in.readInt();
            data2 = in.readInt();
        }
    
    
        public int getData2() {
            return data2;
        }
    
        public void setData2(int data2) {
            this.data2 = data2;
        }
    
        public int getData1() {
            return data1;
        }
    
        public void setData1(int data1) {
            this.data1 = data1;
        }
    
        @Override
        public String toString() {
            return "data1 = "+ data1 + ", data2="+ data2;
        }
    }
    

    1.5 运行

    该工程会生成一个apk,安装到手机,打开apk,界面如下:

    apk

    界面上有三个按钮,分别是功能分别是bindService(绑定Service), unbindService(解除绑定Service), killProcess(杀死Service进程)。

    从左往右,依次点击界面,可得:

    apk

    二、原理分析

    调用图:

    aidl image

    2.1 源码

    采用AIDL技术,是原理还是利用framework binder的架构。本文的实例AIDL会自动生成一个与之相对应的IRemoteService.java文件,如下:

    package com.gityuan.appbinderdemo;
    public interface IRemoteService extends android.os.IInterface {
        public static abstract class Stub extends android.os.Binder implements com.gityuan.appbinderdemo.IRemoteService {
            private static final java.lang.String DESCRIPTOR = "com.gityuan.appbinderdemo.IRemoteService";
    
            /**
             * Stub构造函数
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * 将IBinder 转换为IRemoteService interface
             */
            public static com.gityuan.appbinderdemo.IRemoteService asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.gityuan.appbinderdemo.IRemoteService))) {
                    return ((com.gityuan.appbinderdemo.IRemoteService) iin);
                }
                return new com.gityuan.appbinderdemo.IRemoteService.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_getPid: {
                        data.enforceInterface(DESCRIPTOR);
                        int _result = this.getPid();
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                    case TRANSACTION_getMyData: {
                        data.enforceInterface(DESCRIPTOR);
                        com.gityuan.appbinderdemo.MyData _result = this.getMyData();
                        reply.writeNoException();
                        if ((_result != null)) {
                            reply.writeInt(1);
                            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                        } else {
                            reply.writeInt(0);
                        }
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            private static class Proxy implements com.gityuan.appbinderdemo.IRemoteService {
                private android.os.IBinder mRemote;
    
                /**
                 * Proxy构造函数
                 */
                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 getPid() 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_getPid, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    
                @Override
                public com.gityuan.appbinderdemo.MyData getMyData() throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    com.gityuan.appbinderdemo.MyData _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_getMyData, _data, _reply, 0);
                        _reply.readException();
                        if ((0 != _reply.readInt())) {
                            _result = com.gityuan.appbinderdemo.MyData.CREATOR.createFromParcel(_reply);
                        } else {
                            _result = null;
                        }
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    
            static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_getMyData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    
        public int getPid() throws android.os.RemoteException;
    
        public com.gityuan.appbinderdemo.MyData getMyData() throws android.os.RemoteException;
    }
    Always Believe Something Beauitful Will Be Happen
  • 相关阅读:
    python接口之request测试:以json格式发送post请求,.json方法,查看响应结果的情况
    python字典转化成json格式。JSONEncoder和JSONDecoder两个类来实现Json字符串和dict类型数据的互相转换
    webservice接口测试wsdl,参数是xml格式。python,入参转化成str,返回值转化成dict调用
    jenkins配置自动发送邮件,抄送
    让 Python 的1、数据库查询返回字典记录--- 2、利用zip函数将两个列表(list)组成字典(dict)
    如何从日期对象python获取以毫秒(秒后3位小数)为单位的时间值?
    Python之测试webservice接口
    eclipese pyDEV安装----可以直接运行python文件
    jenkins安装与配置---windows系统,war直接运行
    python pip 安装第三方库 mysql模块步骤--pip install mysql-connector-python
  • 原文地址:https://www.cnblogs.com/Oude/p/12363388.html
Copyright © 2020-2023  润新知