Binder机制-代码实现

Android知识总结

一、Binder通信实现

1.1、model类

public class Person implements Parcelable {

    private String name;
    private int grade;

    public Person(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }

    protected Person(Parcel in) {
        this.name = in.readString();
        this.grade = in.readInt();
    }

    public static final Creator CREATOR = new Creator() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(grade);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", grade=" + grade +
                '}';
    }
}

1.2、接口类

public interface IPersonManager extends IInterface {

    void addPerson(Person person) throws RemoteException;

    List getPersonList() throws RemoteException;
}

1.3、Proxy 类

Proxy 用于客户端的实现

public class Proxy implements IPersonManager {
    //IPersonManager 的描述符
    private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";

    private IBinder mRemote;

    public Proxy(IBinder remote) {
        mRemote = remote;
    }

    @Override
    public void addPerson(Person person) throws RemoteException {
        //用于client向service中写入数据,打包成data
        Parcel data = Parcel.obtain();
        //用于client从service中读取数据,打包成reply
        Parcel reply = Parcel.obtain();
        try {
            //检测
            data.writeInterfaceToken(DESCRIPTOR);
            if ((person != null)) {
                //不为空时写入标识符1,用来service判定是否为空数据,从而序列化数据
                data.writeInt(1);
                //把person写入到 Parcel 中,就是序列化
                person.writeToParcel(data, 0);
            } else {
                //标识符为0时,为空数据
                data.writeInt(0);
            }
            Log.e("leo", "Proxy,addPerson: " + Thread.currentThread());
            //用 transact 向 service 发出命令,用于跨进程,client 挂起(同步的情况)
            mRemote.transact(Stub.TRANSACTION_addPerson, data, reply, 0);
            reply.readException();
        } finally {
            reply.recycle();
            data.recycle();
        }
    }

    @Override
    public List getPersonList() throws RemoteException {
        //用于向service中写入数据
        Parcel data = Parcel.obtain();
        //用于client从service中读取数据
        Parcel reply = Parcel.obtain();
        List result;
        try {
            //检测
            data.writeInterfaceToken(DESCRIPTOR);
            //用 transact 向 service 发出命令,用于跨进程,client 挂起
            mRemote.transact(Stub.TRANSACTION_getPersonList, data, reply, 0);
            reply.readException();
            //获取数据,从service中获取
            result = reply.createTypedArrayList(Person.CREATOR);
        } finally {
            reply.recycle();
            data.recycle();
        }
        return result;
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }
}
  • 主要在三件事
  • 1、打包两个 Parcel 数据
  • 2、检测
  • 3、transact 跨进程通信,并挂起

1.4、Stub 类

Stub 用于服务端的实现,必须继承 Binder

public abstract class Stub extends Binder implements IPersonManager {

    private static final String DESCRIPTOR = "com.enjoy.binder.common.IPersonManager";
     //向binder中注入描述符
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * 判断是同一个进程还是跨进程
     *
     * @param binder
     * @return
     */
    public static IPersonManager asInterface(IBinder binder) {
        if ((binder == null)) {
            return null;
        }
        //如果是跨进程返回为 null
        IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
        //同一个进程
        if ((iin != null) && (iin instanceof IPersonManager)) {
            return (IPersonManager) iin;
        }
        //跨进程
        return new Proxy(binder);
    }

    @Override
    public IBinder asBinder() {
        return this;
    }

    /**
     * 接收client发出的命令
     *
     * @param code  标识符
     * @param data
     * @param reply
     * @param flags
     * @return
     * @throws RemoteException
     */
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case INTERFACE_TRANSACTION:
                //
                reply.writeString(DESCRIPTOR);
                return true;

            case TRANSACTION_addPerson:
                Log.e("leo", "Stub,TRANSACTION_addPerson: " + Thread.currentThread());
                //执行这个描述符的服务
                data.enforceInterface(DESCRIPTOR);
                Person arg0 = null;
                //不为0时写于数据
                if ((0 != data.readInt())) {
                    //从Parcel中读取数据,就是反序列化
                    arg0 = Person.CREATOR.createFromParcel(data);
                }
                this.addPerson(arg0);
                reply.writeNoException();
                return true;

            case TRANSACTION_getPersonList:
                data.enforceInterface(DESCRIPTOR);
                //this 指的是 RemoteService 服务
                List result = this.getPersonList();
                reply.writeNoException();
                //向client返回结果
                reply.writeTypedList(result);
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

    //client 和 service 之间的标识
    static final int TRANSACTION_addPerson = IBinder.FIRST_CALL_TRANSACTION;
    static final int TRANSACTION_getPersonList = IBinder.FIRST_CALL_TRANSACTION + 1;
}
  • asInterface 主要做的事情
  • 1、返回 IInterface == null,表示跨进程。返回 Proxy(binder)
  • 2、返回 IInterface != null,表示同进程,直接返。
  • onTransact
  • 1、根据 code 判断 clien向service端调用的方法
  • 2、this.xxx 调用我们创建 Service 里面 stub 里的方法
  • 3、通过 reply 向 Client 发送信息

1.5、Service 端

public class RemoteService extends Service {

    private ArrayList persons;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        Log.e("LeoAidlService", "success onBind");
        return iBinder;
    }

    private IBinder iBinder = new Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
            persons.add(person);
        }

        @Override
        public List getPersonList() throws RemoteException {
            return persons;
        }
    };
}

1.6、client 实现类

public class ClientActivity extends AppCompatActivity {

    private IPersonManager iPersonManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, RemoteService.class);
        intent.setAction("com.enjoy.binder");
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.e("leo", "------------onClick:" + Thread.currentThread());
                    iPersonManager.addPerson(new Person("leo", 3));
                    List persons = iPersonManager.getPersonList();
                    Log.e("leo", persons.toString() + "," + Thread.currentThread());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("leo", "onServiceConnected: success");
            iPersonManager = Stub.asInterface(service);// 返回 proxy,即 Client
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("leo", "onServiceDisconnected: success");
            iPersonManager = null;
        }
    };
}

1.7、AndroidManifest.xml

        
            
                

                
            
        

        
            
                
                
            
        

二、AIDL 实现

2.1、支持的数据类型

  • 1、Java 的基本数据类型
  • 2、List 和 Map
    1)、元素必须是 AIDL 支持的数据类型
    2)、Server 端具体的类里则必须是 ArrayList 或者 HashMap
  • 3、其他 AIDL 生成的接口
  • 4、实现 Parcelable 的实体
public class Person implements Parcelable {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    protected Person(Parcel in) {
        name = in.readString();
    }

    public static final Creator CREATOR = new Creator() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
    }
}

2.2、AIDL 编写

AIDL 的编写主要为以下三部分:

  • 1、创建 AIDL
    1)、创建要操作的实体类,实现 Parcelable 接口,以便序列化/反序列化
    2)、新建 aidl 文件夹,在其中创建接口 aidl 文件以及实体类的映射 aidl 文件
    3)、Make project ,生成 Binder 的 Java 文件
   // Person.aidl  实体类的映射 aidl 文件
    package net.sxkeji.shixinandroiddemo2.bean;

    //还要和声明的实体类在一个包里
    parcelable Person;
    // IMyAidl.aidl  接口 aidl 文件
    package net.sxkeji.shixinandroiddemo2;

    // Declare any non-default types here with import statements
    import net.sxkeji.shixinandroiddemo2.bean.Person;

    interface IMyAidl {
       /**
         * 除了基本数据类型,其他类型的参数都需要标上方向类型:in(输入), out(输出), inout(输入输出)
         */
        void addPerson(in Person person);
  
        List getPersonList();
    }
  • 2、服务端
    1)、创建 Service,在其中创建上面生成的 Binder 对象实例,实现接口定义的方法
    2)、在 onBind() 中返回

public class PersonService extends Service {
    private static final String TAG = "PersonService";
    private CopyOnWriteArrayList mPerson;
 
    private Binder mBinder = new IPersonService.Stub() {
        @Override
        public List getPersonList() throws RemoteException {
            return mPerson;
        }
 
        @Override
        public void addPerson(Person person) throws RemoteException {
            mPerson.add(person);
        }
    };
 
    @Override
    public void onCreate() {
        super.onCreate();
        init();
    }
 
    private void init() {
        mPerson = new CopyOnWriteArrayList<>();
    }
 
 
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
  • 3、客户端
    1)、实现 ServiceConnection 接口,在其中拿到 AIDL 类
    2)、bindService()
    3)、调用 AIDL 类中定义好的操作请求
    private IPersonService mPersonService;
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mPersonService = IPersonService.Stub.asInterface(service);
            if (mPersonService == null) {
                Log.i(TAG, "mPersonService == null");
                return;
            }
        }
 
        @Override
        public void onServiceDisconnected(ComponentName name) {
 
        }
    };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        Intent intent = new Intent(this, PersonService.class);
        intent.setPackage(PKG_NAME);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

三、Messenger 实现 AIDL

3.1、简介

Messenger它是一种轻量级的IPC 方法,我们使用起来也是非常的简单。他是使用Handler对AIDL进行了一次封装,一次只能处理一个请求。并且Messenger在发送Message的时候不能使用他的obj字段,我们可以用bundle来代替。最后还有一点就是Messenger只是在客户端与服务端跨进程的传递数据,而不能够去访问服务端的方法。

Messenger的使用步骤:
  其实对于Messenger用起来是非常简单的,那么我们首先来看一下这个Messenger的使用步骤:
  1. 在服务端我们实现一个 Handler,接收来自客户端的每个调用的回调
  2. 这个Handler 用于创建 Messenger 对象(也就是对 Handler 的引用)
  3. 用Messenger 创建一个 IBinder,服务端通过 onBind() 使其返回客户端
  4. 客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务端
  5. 服务端在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message

3.2、service端

public class HandlerService extends Service {
    public static final int MESSAGE_TAG_1 = 1;
    public static final int MESSAGE_TAG_2 = MESSAGE_TAG_1 + 1;
    public static final int MESSAGE_TAG_3 = MESSAGE_TAG_2 + 1;

    private Messenger serviceMessage = new Messenger(new BinderHandler());
    public HandlerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return serviceMessage.getBinder();
    }

    private class BinderHandler extends Handler{
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Bundle data = msg.getData();
            if(null == data){
                return;
            }
            switch (msg.what){
                case MESSAGE_TAG_1:
                    String message = data.getString("message");
                    Toast.makeText(HandlerService.this, message, Toast.LENGTH_LONG).show();
                    break;
                case MESSAGE_TAG_2:
                    String str = data.getString("data");
                    Toast.makeText(HandlerService.this, str, Toast.LENGTH_LONG).show();
                    Message toClient = Message.obtain();
                    toClient.what = MESSAGE_TAG_3;
                    toClient.arg1 = 11111;
                    try {
                        //向客户端发送消息
                        msg.replyTo.send(toClient);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    }
}

3.3、client端

 public class MainActivity extends AppCompatActivity { 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        
        Intent intent = new Intent(this, HandlerService.class);
        intent.setAction("com.example.myapplication.service");
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
 
        findViewById(R.id.click_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = Message.obtain();
                message.what = HandlerService.MESSAGE_TAG_2;
                Bundle bundle = new Bundle();
                bundle.putString("data", "发送消息");
                message.setData(bundle);
                message.replyTo = clientMessenger;
                try {
                    messenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                } 
            }
        });
    }
    
    private Messenger messenger = null;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            Message message = Message.obtain();
            message.what = HandlerService.MESSAGE_TAG_1;
            Bundle bundle = new Bundle();
            bundle.putString("message", "建立连接");
            message.setData(bundle);
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            messenger = null;
        }
    };

    //接受客户端消息
    private Messenger clientMessenger = new Messenger(new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == HandlerService.MESSAGE_TAG_3) {
                Toast.makeText(MainActivity.this, msg.arg1 + "", Toast.LENGTH_LONG).show();
            }
        }
    });

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

客户端绑定服务端,获取远程Messenger的binder对象。调用Messenger的send函数,就可以吧Message发送至服务端的Handler。

同时,如果需要服务端回调客户端(往客户端的Handler发消息),则可以在send的Message中设置replyTo,服务端就可以往客户端发送消息了。

Messenger与 AIDL 比较:

  • 当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。
  • 对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口

3.4、发送流程

调用Messenger#send方法发送消息:

    private final IMessenger mTarget;

    //构造函数
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

IMessenger.aidl #send的方法:

oneway interface IMessenger {
    void send(in Message msg);
}

Handler.getIMessenger()返回的是一个IMessenger的binder对象,它的send方法将会调用Handler的sendMessage方法。

源码

你可能感兴趣的:(Binder机制-代码实现)