android 不依靠aidl,自己实现Binder间通信

依靠aidl编写Binder间的通信,确实很方便,只要写好接口,Android Studio编译一下,就会在Project目录->app->generated->source->aidl->debug->包名目录下自动生成代码。为了加深理解,本文决定自己手动实现Binder客户端和服务端的通信,参考了android开发艺术探索这本书籍。

先开始编写服务端,首先自定义一个接口,这个接口继承自IInterface,接着声明一个函数,提供给客户端调用,并且给这个函数定义一个ID。

public interface ICalculationManager extends IInterface {
    private static final int TRANSACTION_doCalculate = (IBinder.FIRST_CALL_TRANSACTION + 0);
    double doCalculate(double a, double b) throws RemoteException;
}

在客户端绑定服务端的时候,会调用Server的onBind,我们需要返回一个Binder对象,并要实现声明的函数。

public class MyServer extends Service {
    private static final String TAG = "MyServer";
    private final ICalculationManager.Stub  mBinder = new ICalculationManager.Stub() {
        @Override
        public double doCalculate(double a, double b) {
            return a + b;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return mBinder;
    }
}

现在可以实现Stub,Stub继承Binder类并实现了接口ICalculationManager,增加了DESCRIPTOR,实现了Stub的构造函数。最重要的是onTransact这个函数,这个函数用来处理客户端要调用的函数和传来的参数,并将结果返回。来看它的第一个参数code,code指的就是函数的ID,通过客户端发过来的id,来决定调用哪个函数。第二个参数data,就是客户端传过来的参数。第三个参数reply用来存放返回结果。这里onTransact里用根据code里的id号switch语句中对应分支,首先从data中读出参数,再经过this.doCalculate的计算,得到结果,写到reply中,this.doCalculate实现就是我们在MyServer中重写的doCalculate。还有其中的asBinder返回的是当前Binder对象,这里就是返回Stub对象。

public interface ICalculationManager extends IInterface {
    private static final String DESCRIPTOR ="com.weather.manual.ICalculationManager";
    private static final int TRANSACTION_doCalculate = (IBinder.FIRST_CALL_TRANSACTION + 0);
    double doCalculate(double a, double b) throws RemoteException;
    abstract class Stub extends Binder implements ICalculationManager{

    public Stub(){this.attachInterface(this,DESCRIPTOR);}
    @Override
      public IBinder asBinder() {
          return this;   
      } 
        @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_doCalculate:
              {
                  data.enforceInterface(DESCRIPTOR);
                  double _arg0;
                  _arg0 = data.readDouble();
                  double _arg1;
                  _arg1 = data.readDouble();
                  double _result = this.doCalculate(_arg0,_arg1);
                  reply.writeNoException();
                  reply.writeDouble(_result);
                  return true;
              }
          }
          return super.onTransact(code, data, reply, flags);
      }

    }
}

服务端的Binder写完了,还要在xml中添加server信息。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.weather.manualserver">

    <application
        /*
         ......
        */

        <service android:name=".MyServer">
            <intent-filter>
                <action android:name="com.weather.manualserver.MyServer"></action>
            </intent-filter>
        </service>


    </application>

</manifest>

在MainActivity中添加启动server的代码。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(MainActivity.this,MyServer.class);
        startService(intent);
    }
}

接下来开始编写客户端里的代码,定义一个ServiceConnection对象,与Service连上就返回一个对象,我们这里返回的是Binder代理对象mICalculationManager,因为是不同进程间的通信。在onCreate中的onClick中调用doCalculate。我们要实现asInterface的代码和客户端doCalculate的代码。

  ICalculationManager mICalculationManager;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: ");
            mICalculationManager = ICalculationManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected: ");
            mICalculationManager = null;
        }
    };

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

        editText_one = (EditText)findViewById(R.id.ed_one);
        editText_two = (EditText)findViewById(R.id.ed_two);
        textView_result = (TextView)findViewById(R.id.tv_result);

        Intent intent = new Intent("com.weather.manualserver.MyServer");
        bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);
        findViewById(R.id.btn_clicked).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    double one = Double.parseDouble(editText_one.getText().toString());
                    double two = Double.parseDouble(editText_two.getText().toString());
                    double result = mICalculationManager.doCalculate(one,two);
                    textView_result.setText(String.valueOf(result));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

接下来实现asInterface的代码,传进来的参数obj是驱动提供给我们的,这里根据判断的是本地进程通信还是进程间通信,

是进程间通信就返回代理对象,是本地通信,就直接返回Binder对象本体。

   public static ICalculationManager asInterface(IBinder obj){
          if(obj == null){
              return  null;
          }
          Log.d(TAG, "asInterface: ");
          IInterface iInterface = obj.queryLocalInterface(DESCRIPTOR);
          if((iInterface!=null)&&(iInterface instanceof ICalculationManager)){
                return (ICalculationManager)iInterface;
          }
          return new ICalculationManager.Stub.Proxy(obj);
      }

然后看代理对象的实现,代理对象中,主要看实现了doCalculate。将参数写入data中,并调用transact函数,传入的参数是要调用的函数的id号,还有参数、返回值和标志位,与onTransact函数的参数很像,执行完后,从reply中读取结果返回。

private static class Proxy implements ICalculationManager {

          private IBinder mRemote;

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

          @Override
          public double doCalculate(double a, double b) throws RemoteException {
              Parcel _data = Parcel.obtain();
              Parcel _reply = Parcel.obtain();
              double _result;

              try {
                  _data.writeInterfaceToken(DESCRIPTOR);
                  _data.writeDouble(a);
                  _data.writeDouble(b);
                  mRemote.transact(Stub.TRANSACTION_doCalculate,_data,_reply,0);
                  _reply.readException();
                  _result = _reply.readDouble();
              }finally {
                  _reply.recycle();
                  _data.recycle();
              }
              return _result;
          }

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

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值