Binder之AIDL

AIDL简介

AIDL (Android Interface Definition Language)是Android内部进程通信(IPC)的接口定义语言,通过它可以定义客户端与服务器端的通信接口,实现跨进程通信。

我的理解就是:Android中的AIDL就是对使用Binder进行进程间通信过程的封装,只需要定义好接口,服务端实现接口,客户端获得Binder代理对象,直接调用服务,中间发送数据,接受数据,处理数据 统统有AIDL完成。

非AIDL实现Binder进程间通信
Binder机制
Binder服务分为两种,一种是实名服务、一种是匿名服务。

实名服务是指Binder在ServiceManager中注册过,可以通过名字查询到该Binder。可以通过ServiceManager.addService(“服务名”)添加服务,ServiceManager.getService(“服务名”)查询服务。要使用ServiceManager得先获得系统开发权限

匿名服务就是没有在ServiceManager注册过的Binder。通过bindService方法,建立binder通信。

一个远程对象的基接口,是为高性能而设计的轻量级远程调用机制的核心部分,它不仅用于远程调用,也可以用于进程内调用。这个接口描述了与远程对象进行交互的抽象协议。建议继承Binder类,而不是直接实现这个接口。
IBinder的主要API是transact(),与它对应另一个方法是Binder.onTransact。第一个方法使你可以向远端的IBinder对象发送调用,第二个方法使你自己的远程对象能够响应接收到的调用。IBinder的API都是同步执行的,比如transact()直到对方的Binder.onTransact()方法调用完成后才返回。而在跨进程的时候,在IPC的帮助下,也是同样的效果。

通过transact()发送的数据是Parcel,Parcel是一种一般的缓冲区,除了有数据外还带有一些描述它内容的元数据。元数据用于管理IBinder对象的引用,这样就能在缓冲去从一个进程移动到另一个进程时,保存这些引用。这样就保证了当一个IBinder被写入到Parcel并发送到另一个进程中,如果另一个进程把同一个IBinder的引用回发到原来的进程,那么这个原来的进程就能接收到发出的那个IBinder的引用。这种机制使IBinder和Binder像唯一标志符那样在进程间管理。

下面用一个demo来说明:

Server端

package com.demo.binderdemo;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;


public class MyService extends Service {

    public static final int TRANSACTION= 0x001;
    private ServerBinder mBinder=new ServerBinder();


    //这里可以简单理解为将可以被其他进程调用的对象告知系统。
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    //进程Binder类,Binder类本身已经实现了IBinder接口
    //这样ServerBinder的对象就可以通过Binder机制被其他进程访问。
    private class ServerBinder extends Binder{
        //onTransact会被Binder的transact调用
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {

            switch (code){
                case TRANSACTION:{
                    int num;
                    num = data.readInt();//读取data中的数据
                    num++;
                    reply.writeNoException();
                    reply.writeInt(num);将数据写入reply
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
    }
}

新建一个Servcie,在Service定义ServerBinder内部类,继承Binder,Binder是Android为我们实现好的Binder本地对象的一个基类,通过继承这个类,实现自己不同的服务。其中onTransact方法是用来接受Client端发送的请求和数据,并将处理后的数据返回给Client。

同时在AndroidManifest.xml中将MyService设置为远程进程。

        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote"  ></service>

再来看Client

package com.demo.binderdemo;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import static com.demo.binderdemo.MyService.TRANSACTION;

public class MainActivity extends Activity {

    private TextView tv_binder;
    private IBinder clientBinder;
    private ServiceConnection connection= new ServiceConnection() {
        //当客户端与服务端建立通信成功时,将回调onServiceConnected

        /**
         * 接收服务端Binder对象的代理对象BinderProxy;
         * @param name
         * @param service
         */

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            //获取服务端Binder对象的代理对象BinderProxy
            clientBinder=service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

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

        tv_binder= (TextView) findViewById(R.id.tv_binder);
        Intent bindIntent=new Intent(this,MyService.class);
        bindService(bindIntent,connection,BIND_AUTO_CREATE);//绑定服务,建立服务端与客户端的通信
        Button btn_binder= (Button) findViewById(R.id.btn_binder);
        btn_binder.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                GetData();
            }
        });

    }

    private void GetData(){
        Parcel _data = Parcel.obtain();
        Parcel _reply = Parcel.obtain();

        try {
            int _result;
            _data.writeInt(Integer.decode(tv_binder.getText().toString()));//将数据存入_data

            //向服务端发送数据
            clientBinder.transact(TRANSACTION,_data, _reply, 0);
            _reply.readException();
            _result = _reply.readInt();//获取服务端的返回数据
            tv_binder.setText(_result+"");

        } catch (RemoteException e) {
            e.printStackTrace();
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
    }


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

实现ServiceConnection接口,在onServiceConnected方法中获取ServerBinder的代理对象,调用bindService,建立Binder通信。

GetData方法是通过Binder代理对象,向服务端发送数据,并接受服务端的返回数据。

从上述代码中可以看出,在Client端我们需要准备数据、发送数据、接受Server端返回的数据,Server端我们需要接受数据、处理数据、返回给Client端数据,虽然很简单,但是如果Server端提供的服务有很多,写起来还是很麻烦,AIDL对上述过程进程的封装,我们只需要在Server端实现服务,Client获取Binder代理对象后,直接调用就可以了,中间数据处理 数据发送、数据接受的过程就不需要管了。
下面用一个银行办理业务的Demo来说明
以Android Studio为例

第一步新建AIDL接口
File–>New–>AIDL–>AIDL File

// IBankAIDL.aidl
package com.demo.binderdemoaidl;

// Declare any non-default types here with import statements

interface IBankAIDL {

    //开户
    String openAcount(String name,String password);
    //存钱
    String saveMoney(int money,String account);
    //取钱
    String takeMoney(int money,String account,String password);
    //销户
    String closeAccount(String account,String password);

}

然后Build–>Make Project
这里写图片描述

在此目录下会生成IBankAIDL.Java文件

UML图如下:
这里写图片描述

Stub是一个抽象类继承了Binder类和IBankAIDL接口
Proxy是Stub中的内部类,主要是用来对Binder代理对象进行装饰

先来看一下Proxy

        private static class Proxy implements com.demo.binderdemoaidl.IBankAIDL {
            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;
            }
//开户

            @Override
            public java.lang.String openAcount(java.lang.String name, java.lang.String password) 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(name);
                    _data.writeString(password);
                    mRemote.transact(Stub.TRANSACTION_openAcount, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
//存钱

            @Override
            public java.lang.String saveMoney(int money, java.lang.String account) 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.writeInt(money);
                    _data.writeString(account);
                    mRemote.transact(Stub.TRANSACTION_saveMoney, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
//取钱

            @Override
            public java.lang.String takeMoney(int money, java.lang.String account, java.lang.String password) 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.writeInt(money);
                    _data.writeString(account);
                    _data.writeString(password);
                    mRemote.transact(Stub.TRANSACTION_takeMoney, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
//销户

            @Override
            public java.lang.String closeAccount(java.lang.String account, java.lang.String password) 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(account);
                    _data.writeString(password);
                    mRemote.transact(Stub.TRANSACTION_closeAccount, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

Proxy继承了IBankAIDL接口并实现了具体的方法
Proxy中的成员变量mRemote是Binder的代理对象,通过代理对象就可以和服务端进程通信,通信的过程封装在了每个方法中,不需要我们自己再去写。

再来看Stub,其有三个方法

asInterface方法

public static com.demo.binderdemoaidl.IBankAIDL asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.demo.binderdemoaidl.IBankAIDL))) {
                return ((com.demo.binderdemoaidl.IBankAIDL) iin);
            }
            return new com.demo.binderdemoaidl.IBankAIDL.Stub.Proxy(obj);
        }

asInterface这个方法就是将获得的Binder代理对象使用Proxy类进程包装一下,Proxy使用这个Binder代理对象向Server端发送数据。


asBinder方法

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

这个方法很简单,返回当前的Binder本地对象。



onTransact方法

        @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_openAcount: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    java.lang.String _result = this.openAcount(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                case TRANSACTION_saveMoney: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    java.lang.String _result = this.saveMoney(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                case TRANSACTION_takeMoney: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    java.lang.String _arg2;
                    _arg2 = data.readString();
                    java.lang.String _result = this.takeMoney(_arg0, _arg1, _arg2);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                case TRANSACTION_closeAccount: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    java.lang.String _result = this.closeAccount(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

这个方法前面介绍过,是用来接受服务端发送过来的数据、处理数据、返回数据的,这个过程也被封装到了AIDL中。

以上三个方法是实现好的,使用Stub时,只需实现IBankAIDL接口的函数即可。

下面来看一下如何使用:

Server端:

新建BankService,并设置为远程服务

package com.demo.binderdemoaidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

public class BankService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return new BankBinder();
    }


    public class BankBinder extends IBankAIDL.Stub {

        private int total=0;
        /**
         * 开户
         * @param name 户主名字
         * @param password  密码
         * @return 开户信息
         * @throws RemoteException
         */
        @Override
        public String openAcount(String name, String password) throws RemoteException {
            return name+"开户成功!账号为:"+ "6354726354627";
        }

        /**
         * 存钱
         * @param money 金额
         * @param account 账户
         * @return 存钱信息
         * @throws RemoteException
         */
        @Override
        public String saveMoney(int money, String account) throws RemoteException {
            total=total+money;
            return "账户:"+account+" 存入"+money+"单位:人民币"+" 余额:"+total+"单位:人民币";
        }

        /**
         * 取钱
         * @param money 取钱信息
         * @param account 账户
         * @param password 密码
         * @return
         * @throws RemoteException
         */
        @Override
        public String takeMoney(int money, String account, String password) throws RemoteException {
            total= total-money;
            return "账户:"+account+"支取"+money+"单位:人民币"+" 余额:"+total+"单位:人民币";
        }

        /**
         * 销户
         * @param account 账户
         * @param password 密码
         * @return 销户信息
         * @throws RemoteException
         */
        @Override
        public String closeAccount(String account, String password) throws RemoteException {
            return account+"销户成功";
        }
    }
}

在BankService中新建一个内部类,继承IBankAIDL.Stub接口,并实现IBankAIDL接口的方法

Client端:

package com.demo.binderdemoaidl;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements View.OnClickListener{

    private IBankAIDL mBankBinder;
    private TextView tv_binder;
    private ServiceConnection conn=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBankBinder=IBankAIDL.Stub.asInterface(service);
            Log.i("ComponentName",name+"");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //绑定Service
        bindService(new Intent(this,BankService.class),conn,BIND_AUTO_CREATE);
        tv_binder= (TextView) findViewById(R.id.tv_binder);

        init(R.id.aidl_bank_open_btn);
        init(R.id.aidl_bank_save_btn);
        init(R.id.aidl_bank_take_btn);
        init(R.id.aidl_bank_close_btn);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
    private void init(int resID){
        Button b= (Button) findViewById(resID);
        b.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        try{
            switch (v.getId()){
                case R.id.aidl_bank_open_btn:
                    tv_binder.setText(mBankBinder.openAcount("小文","123456"));
                    break;
                case R.id.aidl_bank_save_btn:
                    tv_binder.setText(mBankBinder.saveMoney(2000,"6354726354627"));
                    break;
                case R.id.aidl_bank_take_btn:
                    tv_binder.setText(mBankBinder.takeMoney(1000,"6354726354627","123456"));
                    break;
                case R.id.aidl_bank_close_btn:
                    tv_binder.setText(mBankBinder.closeAccount("6354726354627","123456"));
                    break;

            }
        }
        catch (Exception e){
            e.printStackTrace();
        }

    }
}

在onServiceConnected中获取Binder代理对象并调用IBankAIDL.Stub.asInterface方法对Binder代理对象进行包装得到mBankBinder,通过bindService建立binder通信,这样就可以使用mBankBinder与Server端BankBinder进程通信。

UML图:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/fighting_sxw/article/details/79170376