zoukankan      html  css  js  c++  java
  • Android 手写Binder 教你理解android中的进程间通信

    关于Binder,我就不解释的太多了,网上一搜资料一堆,但是估计还是很多人理解的有困难。今天就教你如何从 app层面来理解好Binder。

    其实就从我们普通app开发者的角度来看,仅仅对于android应用层的话,Binder就是客户端和服务端进行通信的媒介。

    AIDL就是我们理解Binder 最好的事例。

    我们都知道 我们写好aidl 文件以后,开发工具 会自动帮我们生成好代码。实际上 我们最终apk里面 是只有这些代码的,我们写的aidl文件

    是不会被打包进去的,也就是说aidl文件 实际上 就是我们用来 生成 实际binder代码用的。所以 我们只要能够分析好,ide自动帮我们生成的

    代码,就可以自己手写binder,从而在app层面上真正理解binder的用法和含义 以及原理。

    首先我先来定义一个实体类:Person.java

     1 package com.example.administrator.writebindercodeexample;
     2 
     3 import android.os.Parcel;
     4 import android.os.Parcelable;
     5 
     6 /**
     7  * Created by Administrator on 2016/1/27.
     8  */
     9 public class Person implements Parcelable {
    10 
    11     private String name;
    12 
    13     public void setName(String name) {
    14         this.name = name;
    15     }
    16 
    17     public void setGender(int gender) {
    18         this.gender = gender;
    19     }
    20 
    21     public int getGender() {
    22         return gender;
    23     }
    24 
    25     public String getName() {
    26         return name;
    27     }
    28 
    29     private int gender;
    30 
    31     @Override
    32     public int describeContents() {
    33         return 0;
    34     }
    35 
    36     @Override
    37     public void writeToParcel(Parcel dest, int flags) {
    38         dest.writeString(this.name);
    39         dest.writeInt(this.gender);
    40     }
    41 
    42     public Person() {
    43     }
    44 
    45     protected Person(Parcel in) {
    46         this.name = in.readString();
    47         this.gender = in.readInt();
    48     }
    49 
    50     public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
    51         public Person createFromParcel(Parcel source) {
    52             return new Person(source);
    53         }
    54 
    55         public Person[] newArray(int size) {
    56             return new Person[size];
    57         }
    58     };
    59 }

    注意看  我们这个person 类 是实现了android自带的序列化接口的,所以 如果你要在aidl里使用这个类,那你必须要额外在aidl里生命下 这个类。

    1 // Person.aidl.aidl
    2 package com.example.administrator.writebindercodeexample;
    3 
    4 // Declare any non-default types here with import statements
    5 parcelable Person;
     1 // IPersonManager.aidl
     2 package com.example.administrator.writebindercodeexample;
     3 
     4 // Declare any non-default types here with import statements
     5 import com.example.administrator.writebindercodeexample.Person;
     6 interface IPersonManager {
     7     List<Person> getPersonList();
     8     //关于这个参数in 其实你不加也是可以编译通过的,这里我就先加一下 具体参数的意义 以后会说
     9     void addPerson(in Person person);
    10 }

    好,然后给你们看一下 文件结构:

    好 这里就是一个典型的 应用aidl 技术的 一个例子,我们现在 让studio 编译这个project,然后看看生成的binder代码。 把这份binder代码 分析好了,我们以后就可以不借助ide 来自己手写binder了。

    我们来看看 生成的代码在哪里:

    最后我们来看一下 这个生成的代码 是啥样的:

      1 /*
      2  * This file is auto-generated.  DO NOT MODIFY.
      3  * Original file: C:\Users\Administrator\WriteBinderCodeExample\app\src\main\aidl\com\example\administrator\writebindercodeexample\IPersonManager.aidl
      4  */
      5 package com.example.administrator.writebindercodeexample;
      6 public interface IPersonManager extends android.os.IInterface
      7 {
      8 /** Local-side IPC implementation stub class. */
      9 public static abstract class Stub extends android.os.Binder implements com.example.administrator.writebindercodeexample.IPersonManager
     10 {
     11 private static final java.lang.String DESCRIPTOR = "com.example.administrator.writebindercodeexample.IPersonManager";
     12 /** Construct the stub at attach it to the interface. */
     13 public Stub()
     14 {
     15 this.attachInterface(this, DESCRIPTOR);
     16 }
     17 /**
     18  * Cast an IBinder object into an com.example.administrator.writebindercodeexample.IPersonManager interface,
     19  * generating a proxy if needed.
     20  */
     21 public static com.example.administrator.writebindercodeexample.IPersonManager asInterface(android.os.IBinder obj)
     22 {
     23 if ((obj==null)) {
     24 return null;
     25 }
     26 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
     27 if (((iin!=null)&&(iin instanceof com.example.administrator.writebindercodeexample.IPersonManager))) {
     28 return ((com.example.administrator.writebindercodeexample.IPersonManager)iin);
     29 }
     30 return new com.example.administrator.writebindercodeexample.IPersonManager.Stub.Proxy(obj);
     31 }
     32 @Override public android.os.IBinder asBinder()
     33 {
     34 return this;
     35 }
     36 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
     37 {
     38 switch (code)
     39 {
     40 case INTERFACE_TRANSACTION:
     41 {
     42 reply.writeString(DESCRIPTOR);
     43 return true;
     44 }
     45 case TRANSACTION_getPersonList:
     46 {
     47 data.enforceInterface(DESCRIPTOR);
     48 java.util.List<com.example.administrator.writebindercodeexample.Person> _result = this.getPersonList();
     49 reply.writeNoException();
     50 reply.writeTypedList(_result);
     51 return true;
     52 }
     53 case TRANSACTION_addPerson:
     54 {
     55 data.enforceInterface(DESCRIPTOR);
     56 com.example.administrator.writebindercodeexample.Person _arg0;
     57 if ((0!=data.readInt())) {
     58 _arg0 = com.example.administrator.writebindercodeexample.Person.CREATOR.createFromParcel(data);
     59 }
     60 else {
     61 _arg0 = null;
     62 }
     63 this.addPerson(_arg0);
     64 reply.writeNoException();
     65 return true;
     66 }
     67 }
     68 return super.onTransact(code, data, reply, flags);
     69 }
     70 private static class Proxy implements com.example.administrator.writebindercodeexample.IPersonManager
     71 {
     72 private android.os.IBinder mRemote;
     73 Proxy(android.os.IBinder remote)
     74 {
     75 mRemote = remote;
     76 }
     77 @Override public android.os.IBinder asBinder()
     78 {
     79 return mRemote;
     80 }
     81 public java.lang.String getInterfaceDescriptor()
     82 {
     83 return DESCRIPTOR;
     84 }
     85 @Override public java.util.List<com.example.administrator.writebindercodeexample.Person> getPersonList() throws android.os.RemoteException
     86 {
     87 android.os.Parcel _data = android.os.Parcel.obtain();
     88 android.os.Parcel _reply = android.os.Parcel.obtain();
     89 java.util.List<com.example.administrator.writebindercodeexample.Person> _result;
     90 try {
     91 _data.writeInterfaceToken(DESCRIPTOR);
     92 mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
     93 _reply.readException();
     94 _result = _reply.createTypedArrayList(com.example.administrator.writebindercodeexample.Person.CREATOR);
     95 }
     96 finally {
     97 _reply.recycle();
     98 _data.recycle();
     99 }
    100 return _result;
    101 }
    102 //关于这个参数in 其实你不加也是可以编译通过的,这里我就先加一下 具体参数的意义 以后会说
    103 
    104 @Override public void addPerson(com.example.administrator.writebindercodeexample.Person person) throws android.os.RemoteException
    105 {
    106 android.os.Parcel _data = android.os.Parcel.obtain();
    107 android.os.Parcel _reply = android.os.Parcel.obtain();
    108 try {
    109 _data.writeInterfaceToken(DESCRIPTOR);
    110 if ((person!=null)) {
    111 _data.writeInt(1);
    112 person.writeToParcel(_data, 0);
    113 }
    114 else {
    115 _data.writeInt(0);
    116 }
    117 mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
    118 _reply.readException();
    119 }
    120 finally {
    121 _reply.recycle();
    122 _data.recycle();
    123 }
    124 }
    125 }
    126 static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    127 static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    128 }
    129 public java.util.List<com.example.administrator.writebindercodeexample.Person> getPersonList() throws android.os.RemoteException;
    130 //关于这个参数in 其实你不加也是可以编译通过的,这里我就先加一下 具体参数的意义 以后会说
    131 
    132 public void addPerson(com.example.administrator.writebindercodeexample.Person person) throws android.os.RemoteException;
    133 }

    看上去呢,杂乱无章, 但其实也就是100多行,所以 我调整了一下 这个代码的顺序 ,你们可以看的更清楚,同时也增加了注释:

      1 package com.example.administrator.aidlmessagetest;
      2 
      3 //为了让大家看的更清楚 我把生成的binder代码 给拷贝到另外一个工程下面了,并且用ide 给他format
      4 //所以包名和我们一开始前面的代码都不一样,大家理解意思就行。
      5 
      6 
      7 //从前面几行就能看出来 生成的代码是一个 interface ,只不过这个interface是 android.os.IInterface 的子类!
      8 public interface IPersonManager extends android.os.IInterface {
      9 
     10     //并且这个接口里 有一个静态的抽象类Stub(注意这个名字是固定的 永远都是Stub 不会是其他)
     11     //并且这个Stub是Binder的子类,并且实现了IPersonManager 这个接口
     12     public static abstract class Stub extends android.os.Binder implements com.example.administrator.aidlmessagetest.IPersonManager {
     13         //这个东西就是唯一的binder标示 可以看到就是IPersonManager的全路径名
     14         private static final java.lang.String DESCRIPTOR = "com.example.administrator.aidlmessagetest.IPersonManager";
     15 
     16         /**
     17          * 这个就是Stub的构造方法,回顾一下 我们如果写好aidl文件以后 写的service里面 是怎么写的?
     18          *
     19          * private final IPersonManager.Stub mBinder = new IPersonManager.Stub() {}
     20          * 我们都是这么写的 对吧~~所以想想我们的service里面的代码 就能辅助理解 这里的代码了
     21          */
     22         public Stub() {
     23             this.attachInterface(this, DESCRIPTOR);
     24         }
     25 
     26 
     27         //这个方法 其实就做了一件事,如果是同一个进程,那么就返回Stub对象本身
     28         //如果不是同一个进程,就返回Stub.Proxy这个代理对象了
     29         public static com.example.administrator.aidlmessagetest.IPersonManager asInterface(android.os.IBinder obj) {
     30             if ((obj == null)) {
     31                 return null;
     32             }
     33             android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
     34             //如果是同1个进程,也就是说进程内通信的话 我们就返回括号内里的对象
     35             if (((iin != null) && (iin instanceof com.example.administrator.aidlmessagetest.IPersonManager))) {
     36                 return ((com.example.administrator.aidlmessagetest.IPersonManager) iin);
     37             }
     38             //如果不是同一进程,是2个进程之间相互通信,那我们就得返回这个Stub.Proxy 看上去叫Stub 代理的对象了
     39             return new com.example.administrator.aidlmessagetest.IPersonManager.Stub.Proxy(obj);
     40         }
     41 
     42         //返回当前对象
     43         @Override
     44         public android.os.IBinder asBinder() {
     45             return this;
     46         }
     47 
     48         //只有在多进程通信的时候 才会调用这个方法 ,同一个进程是不会调用的。
     49 
     50         //首先 我们要明白 这个方法 一般情况下 都是返回true的,也只有返回true的时候才有意义,如果返回false了 就代表这个方法执行失败,
     51         //所以我们通常是用这个方法来做权限认证的,其实也很好理解,既然是多进程通信,那么我们服务端的进程当然不希望谁都能过来调用
     52         //所以权限认证是必须的,关于权限认证的代码 以后我再讲 先略过。
     53 
     54         //除此之外 ,onTransact 这个方法 就是运行在Binder线程池中的,一般就是客户端发起请求,然后android底层代码把这个客户端发起的
     55         //请求 封装成3个参数 来调用这个onTransact方法,第一个参数code 就代表客户端想要调用服务端 方法的 标志位。
     56         //其实也很好理解 服务端可能有n个方法 每个方法 都有一个对应的int值来代表,这个code就是这个int值,用来标示客户端想调用的服务端的方法
     57         //data就是方法参数,reply就是方法返回值。都很好理解
     58 
     59         //其实隐藏了很重要的一点,这个方法既然是运行在binder线程池中的,所以在这个方法里面调用的服务器方法也是运行在Binder线程池中的,
     60         //所以我们要记得 如果你的服务端程序 有可能和多个客户端相联的话,你方法里使用的那些参数 必须要是支持异步的,否则的话
     61         //值就会错乱了!这点一定要记住!结论就是Binder方法 一定要是同步方法!!!!!!
     62         @Override
     63         public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
     64             switch (code) {
     65                 case INTERFACE_TRANSACTION: {
     66                     reply.writeString(DESCRIPTOR);
     67                     return true;
     68                 }
     69                 case TRANSACTION_getPersonList: {
     70                     data.enforceInterface(DESCRIPTOR);
     71                     java.util.List<com.example.administrator.aidlmessagetest.Person> _result = this.getPersonList();
     72                     reply.writeNoException();
     73                     reply.writeTypedList(_result);
     74                     return true;
     75                 }
     76                 case TRANSACTION_addPerson: {
     77                     data.enforceInterface(DESCRIPTOR);
     78                     com.example.administrator.aidlmessagetest.Person _arg0;
     79                     if ((0 != data.readInt())) {
     80                         _arg0 = com.example.administrator.aidlmessagetest.Person.CREATOR.createFromParcel(data);
     81                     } else {
     82                         _arg0 = null;
     83                     }
     84                     this.addPerson(_arg0);
     85                     reply.writeNoException();
     86                     return true;
     87                 }
     88             }
     89             return super.onTransact(code, data, reply, flags);
     90         }
     91 
     92         //注意这里的Proxy 这个类名也是不变的,从前文我们知道 只有在多进程通信的情况下  才会返回这个代理的对象
     93         private static class Proxy implements com.example.administrator.aidlmessagetest.IPersonManager {
     94             private android.os.IBinder mRemote;
     95 
     96             Proxy(android.os.IBinder remote) {
     97                 mRemote = remote;
     98             }
     99 
    100             @Override
    101             public android.os.IBinder asBinder() {
    102                 return mRemote;
    103             }
    104 
    105             public java.lang.String getInterfaceDescriptor() {
    106                 return DESCRIPTOR;
    107             }
    108 
    109 
    110             //这里我们一共有2个方法 一个getPersonList 一个addPerson 我们就分析一个方法就可以了
    111             //并且要知道 这2个方法运行在客户端!!!!!!!!!!!!!!!!
    112             //首先就是创建了3个对象_data 输入对象,_reply输出对象,_result返回值对象
    113             //然后把参数信息 写入到_data里,接着就调用了transact这个方法 来发送rpc请求,然后接着
    114             //当前线程挂起, 服务端的onTransace方法才被调用,调用结束以后 当前线程继续执行,直到
    115             //从_reply中取出rpc的返回结果 然后返回_reply的数据
    116 
    117             //所以这里我们就要注意了,客户端发起调用远程请求时,当前客户端的线程就会被挂起了,
    118             //所以如果一个远程方法 很耗时,我们客户端就一定不能在ui main线程里在发起这个rpc请求,不然就anr了。
    119             @Override
    120             public java.util.List<com.example.administrator.aidlmessagetest.Person> getPersonList() throws android.os.RemoteException {
    121                 android.os.Parcel _data = android.os.Parcel.obtain();
    122                 android.os.Parcel _reply = android.os.Parcel.obtain();
    123                 java.util.List<com.example.administrator.aidlmessagetest.Person> _result;
    124                 try {
    125                     _data.writeInterfaceToken(DESCRIPTOR);
    126                     mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
    127                     _reply.readException();
    128                     _result = _reply.createTypedArrayList(com.example.administrator.aidlmessagetest.Person.CREATOR);
    129                 } finally {
    130                     _reply.recycle();
    131                     _data.recycle();
    132                 }
    133                 return _result;
    134             }
    135 
    136             //你看自动生成binder代码的时候 连你的注释也一起拷贝过来了。。。。。是不是很有趣
    137             //关于这个参数in 其实你不加也是可以编译通过的,这里我就先加一下 具体参数的意义 以后会说
    138 
    139             @Override
    140             public void addPerson(com.example.administrator.aidlmessagetest.Person person) throws android.os.RemoteException {
    141                 android.os.Parcel _data = android.os.Parcel.obtain();
    142                 android.os.Parcel _reply = android.os.Parcel.obtain();
    143                 try {
    144                     _data.writeInterfaceToken(DESCRIPTOR);
    145                     if ((person != null)) {
    146                         _data.writeInt(1);
    147                         person.writeToParcel(_data, 0);
    148                     } else {
    149                         _data.writeInt(0);
    150                     }
    151                     mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
    152                     _reply.readException();
    153                 } finally {
    154                     _reply.recycle();
    155                     _data.recycle();
    156                 }
    157             }
    158         }
    159 
    160         static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    161         static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    162     }
    163 
    164     public java.util.List<com.example.administrator.aidlmessagetest.Person> getPersonList() throws android.os.RemoteException;
    165 //关于这个参数in 其实你不加也是可以编译通过的,这里我就先加一下 具体参数的意义 以后会说
    166 
    167     public void addPerson(com.example.administrator.aidlmessagetest.Person person) throws android.os.RemoteException;
    168 }

    到这里 相信大家 至少在应用层上面,就对Binder就一个很直观的理解了,对于进程间通信来说,具体的流程就分为如下几步:

    1.Client 发起远程调用请求 也就是RPC 到Binder。同时将自己挂起,挂起的原因是要等待RPC调用结束以后返回的结果

    2.Binder 收到RPC请求以后 把参数收集一下,调用transact方法,把RPC请求转发给service端。

    3.service端 收到rpc请求以后 就去线程池里 找一个空闲的线程去走service端的 onTransact方法 ,实际上也就是真正在运行service端的 方法了,等方法运行结束 就把结果 写回到binder中。

    4.Binder 收到返回数据以后 就唤醒原来的Client 线程,返回结果。至此,一次进程间通信 的过程就结束了

    搞明白以后 我们就可以来尝试着 手下一下Binder:(前面我们aidl 帮我们生成的binder 是人,也就是person,那这次我们自己写的时候 就用狗吧,用DOG)

    首先定义一个Dog.java: 实际上和person 一样的 所以这里暂时把代码折叠起来。

     1 package com.example.administrator.writebindercodeexample;
     2 
     3 import android.os.Parcel;
     4 import android.os.Parcelable;
     5 
     6 /**
     7  * Created by Administrator on 2016/1/27.
     8  */
     9 public class Dog implements Parcelable {
    10 
    11     public int getGender() {
    12         return gender;
    13     }
    14 
    15     public String getName() {
    16         return name;
    17     }
    18 
    19     public void setGender(int gender) {
    20         this.gender = gender;
    21     }
    22 
    23     public void setName(String name) {
    24         this.name = name;
    25     }
    26 
    27     private int gender;
    28     private String name;
    29 
    30 
    31     @Override
    32     public int describeContents() {
    33         return 0;
    34     }
    35 
    36     @Override
    37     public void writeToParcel(Parcel dest, int flags) {
    38         dest.writeInt(this.gender);
    39         dest.writeString(this.name);
    40     }
    41 
    42     public Dog() {
    43     }
    44 
    45     protected Dog(Parcel in) {
    46         this.gender = in.readInt();
    47         this.name = in.readString();
    48     }
    49 
    50     public static final Parcelable.Creator<Dog> CREATOR = new Parcelable.Creator<Dog>() {
    51         public Dog createFromParcel(Parcel source) {
    52             return new Dog(source);
    53         }
    54 
    55         public Dog[] newArray(int size) {
    56             return new Dog[size];
    57         }
    58     };
    59 }
    View Code

    然后写一个接口IDogManager

     1 package com.example.administrator.writebindercodeexample;
     2 
     3 import android.os.IBinder;
     4 import android.os.IInterface;
     5 import android.os.RemoteException;
     6 
     7 import java.util.List;
     8 
     9 /**
    10  * Created by Administrator on 2016/1/27.
    11  */
    12 public interface IDogManager extends IInterface {
    13 
    14     static final String DESCRIPTOR = "com.example.administrator.writebindercodeexample.IDogManager";
    15     static final int TRANSACTION_getDogList = IBinder.FIRST_CALL_TRANSACTION + 0;
    16     static final int TRANSACTION_addDog = IBinder.FIRST_CALL_TRANSACTION + 1;
    17 
    18     public List<Dog> getDogList() throws RemoteException;
    19 
    20     public void addDog(Dog dog) throws RemoteException;
    21 
    22 }

    然后写我们的binder,注意我们的binder 我这里是写的抽象类,因为你写成实体类的话 就必须要实现IDogManger里的2个方法 ,然而为了结构清晰 我们并不准备把binder 放在service里 实现。

    所以这里binder 我们还是用抽象类来做,然后在service里 实现 getDogList和addDog方法即可。

      1 package com.example.administrator.writebindercodeexample;
      2 
      3 import android.os.Binder;
      4 import android.os.IBinder;
      5 import android.os.Parcel;
      6 import android.os.RemoteException;
      7 
      8 /**
      9  * Created by Administrator on 2016/1/27.
     10  */
     11 public abstract class DogManagerImpl extends Binder implements IDogManager {
     12 
     13     public DogManagerImpl() {
     14         this.attachInterface(this, DESCRIPTOR);
     15     }
     16 
     17     public static com.example.administrator.writebindercodeexample.IDogManager asInterface(android.os.IBinder obj) {
     18         if ((obj == null)) {
     19             return null;
     20         }
     21         android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
     22         //如果是同1个进程,也就是说进程内通信的话 我们就返回括号内里的对象
     23         if (((iin != null) && (iin instanceof com.example.administrator.writebindercodeexample.IDogManager))) {
     24             return ((com.example.administrator.writebindercodeexample.IDogManager) iin);
     25         }
     26         //如果不是同一进程,是2个进程之间相互通信,那我们就得返回这个Stub.Proxy 看上去叫Stub 代理的对象了
     27         return new com.example.administrator.writebindercodeexample.DogManagerImpl.Proxy(obj);
     28     }
     29 
     30 
     31     @Override
     32     public IBinder asBinder() {
     33         return this;
     34     }
     35 
     36     @Override
     37     protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
     38         switch (code) {
     39             case INTERFACE_TRANSACTION: {
     40                 reply.writeString(DESCRIPTOR);
     41                 return true;
     42             }
     43             case TRANSACTION_getDogList: {
     44                 data.enforceInterface(DESCRIPTOR);
     45                 java.util.List<com.example.administrator.writebindercodeexample.Dog> _result = this.getDogList();
     46                 reply.writeNoException();
     47                 reply.writeTypedList(_result);
     48                 return true;
     49             }
     50             case TRANSACTION_addDog: {
     51                 data.enforceInterface(DESCRIPTOR);
     52                 com.example.administrator.writebindercodeexample.Dog _arg0;
     53                 if ((0 != data.readInt())) {
     54                     _arg0 = com.example.administrator.writebindercodeexample.Dog.CREATOR.createFromParcel(data);
     55                 } else {
     56                     _arg0 = null;
     57                 }
     58                 this.addDog(_arg0);
     59                 reply.writeNoException();
     60                 return true;
     61             }
     62         }
     63         return super.onTransact(code, data, reply, flags);
     64     }
     65 
     66     private static class Proxy extends DogManagerImpl {
     67         private android.os.IBinder mRemote;
     68 
     69         Proxy(android.os.IBinder remote) {
     70             mRemote = remote;
     71         }
     72 
     73         @Override
     74         public android.os.IBinder asBinder() {
     75             return mRemote;
     76         }
     77 
     78         public java.lang.String getInterfaceDescriptor() {
     79             return DESCRIPTOR;
     80         }
     81 
     82         @Override
     83         public java.util.List<com.example.administrator.writebindercodeexample.Dog> getDogList() throws android.os.RemoteException {
     84             android.os.Parcel _data = android.os.Parcel.obtain();
     85             android.os.Parcel _reply = android.os.Parcel.obtain();
     86             java.util.List<com.example.administrator.writebindercodeexample.Dog> _result;
     87             try {
     88                 _data.writeInterfaceToken(DESCRIPTOR);
     89                 mRemote.transact(DogManagerImpl.TRANSACTION_getDogList, _data, _reply, 0);
     90                 _reply.readException();
     91                 _result = _reply.createTypedArrayList(com.example.administrator.writebindercodeexample.Dog.CREATOR);
     92             } finally {
     93                 _reply.recycle();
     94                 _data.recycle();
     95             }
     96             return _result;
     97         }
     98 
     99         @Override
    100         public void addDog(com.example.administrator.writebindercodeexample.Dog dog) throws android.os.RemoteException {
    101             android.os.Parcel _data = android.os.Parcel.obtain();
    102             android.os.Parcel _reply = android.os.Parcel.obtain();
    103             try {
    104                 _data.writeInterfaceToken(DESCRIPTOR);
    105                 if ((dog != null)) {
    106                     _data.writeInt(1);
    107                     dog.writeToParcel(_data, 0);
    108                 } else {
    109                     _data.writeInt(0);
    110                 }
    111                 mRemote.transact(DogManagerImpl.TRANSACTION_addDog, _data, _reply, 0);
    112                 _reply.readException();
    113             } finally {
    114                 _reply.recycle();
    115                 _data.recycle();
    116             }
    117         }
    118     }
    119 
    120 }
    View Code

    到这,我们的手写binder 就完成了,然后看看 service 以及客户端 怎么调用。

    先看service:

     1 package com.example.administrator.writebindercodeexample;
     2 
     3 import android.app.Service;
     4 import android.content.Intent;
     5 import android.os.IBinder;
     6 import android.os.RemoteException;
     7 import android.util.Log;
     8 
     9 import java.util.ArrayList;
    10 import java.util.List;
    11 
    12 public class RemoteService extends Service {
    13 
    14     private List<Dog> mDogsList = new ArrayList<Dog>();
    15 
    16     private final DogManagerImpl mBinder = new DogManagerImpl() {
    17         @Override
    18         public List<Dog> getDogList() throws RemoteException {
    19             return mDogsList;
    20         }
    21 
    22         @Override
    23         public void addDog(Dog dog) throws RemoteException {
    24             mDogsList.add(dog);
    25         }
    26     };
    27 
    28     @Override
    29     public IBinder onBind(Intent intent) {
    30         return mBinder;
    31     }
    32 }

    然后看看 启动如何在客户端bind 这个service:

     1 private IDogManager mService;
     2 
     3     private ServiceConnection sc = new ServiceConnection() {
     4         @Override
     5         public void onServiceConnected(ComponentName name, IBinder service) {
     6             mService = DogManagerImpl.asInterface(service);
     7 
     8         }
     9 
    10         @Override
    11         public void onServiceDisconnected(ComponentName name) {
    12             mService = null;
    13         }
    14     };

    到这 就基本写完了,手写binder的好处就是 你可以自己在binder方法里 写一些log,能够更加深刻的认识到 Binder 作为 进程间通信 媒介的重要作用以及原理。

    熟悉以后,还是用aidl 的方法 自动生成代码 最好。

  • 相关阅读:
    C#类中的字段、属性和方法
    Linux下制作Windows启动U盘的工具
    将samba共享目录映射为本地文件夹(百度网盘直接下载到samba共享目录下)
    《怎样编写研究报告》读书笔记0-0
    mcnp的重复探测器单元计数-fmesh卡的介绍
    单能X射线产生方法
    matlab学习之降噪平滑算法
    matlab学习之求解函数的根和极小值
    matlab学习之绘制参数曲线,添加辅助线以及颜色设置
    MC资源整理
  • 原文地址:https://www.cnblogs.com/punkisnotdead/p/5163464.html
Copyright © 2011-2022 走看看