zoukankan      html  css  js  c++  java
  • 4.10Android学习

    一、今日学习内容

    今日继续binder的学习

    根据昨天学习的两个方法我们就可以实现Client和Server端的通信,接下来我们看看具体该怎么使用。 在Server接收到Client传来的消息(data)时,会对data进行验证data.enforceInterface(DESCRIPTOR),DESCRIPTOR是一个字符串类型的描述符,当data的描述符跟DESCRIPTOR相同时才能通过验证。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class Stub extends Binder {
        //描述符
        public static final java.lang.String DESCRIPTOR = "MyTestBinder";
        //code 方法描述符
        public static final int TRANSACTION_test0 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        public static final int TRANSACTION_test1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
     
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
                case TRANSACTION_test0:
                    //验证描述符
                    data.enforceInterface(DESCRIPTOR);
                    //执行方法
                    test0();
                    return true;
                case TRANSACTION_test1:
                    //验证描述符
                    data.enforceInterface(DESCRIPTOR);
                    //执行方法
                    test1(data, reply);
                    return true;
            }
            return super.onTransact(code, data, reply, flags);
        }
     
        //无返回值
        private void test0() {
            Log.d("MyBinderServer", "test0");
        }
     
        //有返回值
        private void test1(Parcel data, Parcel reply) {
            Log.d("MyBinderServer", "test1");
            reply.writeInt(data.readInt() + 1);
        }
    }

    我们知道,要想实现Client和Server端的通信连接,就必须让client知道server端的地址,就跟Http请求,我们要知道服务端的ip和端口。Binder通信其实也是一样的,那么我们怎么让Client拿到Server的地址呢? 一种是跟Http请求一样,我们知道Http请求要把域名转换成ip和端口,这就是DNS,我们也需要一个Binder的DNS。安卓中也为我们提供了Binder的“DNS”那就是ServiceManager,ServiceManager中注册了所有系统服务(如MediaServer等),我们可以使用ServiceManager拿到远程的Binder地址,这种方式叫做有名Binder查找(有名Binder,如MediaServer等这些系统服务被注册的时候都是有名字的,比如,我们通过WINDOW_SERVICE这个名字就能拿到WindowManager)。但是问题是向ServiceManager注册服务的过程是系统进程实现的,我们的应用进程不能注册自己的Binder。 另一种就是利用有名的Binder来辅助传递匿名的Binder,也就是说如果有某个有名Binder服务它提供了传递Binder的方法,那么我们就可以通过这个Binder服务来传递我们的匿名Binder,我们查找到这个有名的Binder是不是就能拿到我们的匿名Binder。正好AMS其实提供了这样的功能,它通过Service.onBind把匿名的Binder封装在了Service里面供我们调用。

    1
    2
    3
    4
    5
    6
    7
    public class MyService extends Service {
         
        @Override
        public IBinder onBind(Intent intent) {
            return new Stub();
        }
    }

    我们使用binderService()来获取远程的Binder。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Intent serviceIntent = new Intent(this, MyService.class);
            bindService(serviceIntent, new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    //service可以理解为是远程Binder的地址,我们利用他跟远程通信,C++层会转换这个IBinder跟Binder进行通信
                }
     
                @Override
                public void onServiceDisconnected(ComponentName name) {
     
                }
            }, BIND_AUTO_CREATE);

    获取到Binder之后我们补充好通信的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    bindService(serviceIntent, new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Parcel data0 = Parcel.obtain();//请求参数
            Parcel reply0 = Parcel.obtain();//响应参数
            Parcel data1 = Parcel.obtain();
            Parcel reply1 = Parcel.obtain();
     
            //调用第一个方法
            try {
                //添加描述符
                data0.writeInterfaceToken(Stub.DESCRIPTOR);
                /*
                 * 写入参数,要想传递多个int参数,顺序调用writeInt
                 * data0.writeInt(10);
                 * data0.writeInt(20);
                 * 获取
                 * int num10 = data0.readInt();
                 * int num20 = data0.readInt();
                 */
                data0.writeInt(10);
                //发起远程调用
                service.transact(Stub.TRANSACTION_test0, data0, reply0, 0);
                reply0.readException();
            } catch (RemoteException e) {
                e.printStackTrace();
            } finally {
                data0.recycle();
                reply0.recycle();
            }
     
            //调用第二个方法
            try {
                //添加描述符
                data1.writeInterfaceToken(Stub.DESCRIPTOR);
                data1.writeInt(10);
                //发起远程调用
                service.transact(Stub.TRANSACTION_test1, data1, reply1, 0);
                reply1.readException();
                //读取返回值
                int num = reply1.readInt();
                Log.d(TAG, "reply value: " + num);
            } catch (RemoteException e) {
                e.printStackTrace();
            } finally {
                data1.recycle();
                reply1.recycle();
            }
        }
     
        @Override
        public void onServiceDisconnected(ComponentName name) {
     
        }
    }, BIND_AUTO_CREATE);

    为了方便调用,我们写一个代理类来封装通信过程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    public class Proxy {
        //描述符
        public static final java.lang.String DESCRIPTOR = "MyTestBinder";
        //code 方法描述符
        public static final int TRANSACTION_test0 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        public static final int TRANSACTION_test1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        private IBinder mRemote;
     
        public Proxy(IBinder remote) {
            this.mRemote = remote;
        }
     
        public void test1() {
            Parcel data0 = Parcel.obtain();//请求参数
            Parcel reply0 = Parcel.obtain();//响应参数
            //调用第一个方法
            try {
                //添加描述符
                data0.writeInterfaceToken(DESCRIPTOR);
                /*
                 * 写入参数,要想传递多个int参数,顺序调用writeInt
                 * data0.writeInt(10);
                 * data0.writeInt(20);
                 * 获取
                 * int num10 = data0.readInt();
                 * int num20 = data0.readInt();
                 */
                data0.writeInt(10);
                //发起远程调用
                mRemote.transact(TRANSACTION_test0, data0, reply0, 0);
                reply0.readException();
            } catch (RemoteException e) {
                e.printStackTrace();
            } finally {
                data0.recycle();
                reply0.recycle();
            }
        }
     
        public int test2() {
            Parcel data1 = Parcel.obtain();
            Parcel reply1 = Parcel.obtain();
            //调用第二个方法
            int num = 0;
            try {
                //添加描述符
                data1.writeInterfaceToken(DESCRIPTOR);
                data1.writeInt(10);
                //发起远程调用
                mRemote.transact(TRANSACTION_test1, data1, reply1, 0);
                reply1.readException();
                //读取返回值
                num = reply1.readInt();
            } catch (RemoteException e) {
                e.printStackTrace();
            } finally {
                data1.recycle();
                reply1.recycle();
            }
            return num;
        }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    bindService(serviceIntent, new ServiceConnection() {
               @Override
               public void onServiceConnected(ComponentName name, IBinder service) {
                   Proxy proxy = new Proxy(service);
                   proxy.test1();
                   int i = proxy.test2();
               }
     
               @Override
               public void onServiceDisconnected(ComponentName name) {
     
               }
           }, BIND_AUTO_CREATE);

    二、遇到的问题

    暂无

    三、明日计划

    继续binder的学习

  • 相关阅读:
    Android textAppearance的属性设置及TextView属性详解
    Eclipse Hot Keys
    面向对象(一)
    Java基础知识(下)
    code2uml使用教程
    AndroidDevTools简介
    idea2020.3 安装插件JetBrains 插件市场安装 Cloud Toolkit
    在 Mac 上撰写和格式化备忘录-添加提醒-添加日历
    macbook-键盘连击问题002
    创业团队建设与管理
  • 原文地址:https://www.cnblogs.com/zyljal/p/14909807.html
Copyright © 2011-2022 走看看