一、 Binder概述


1.1 为什么要用binder

  • 出于安全性、稳定性和内存管理的考虑,Android的应用和系统服务运行在分离的进程中,但是它们之间需要通信和共享数据
  • 避免传统IPC开销和服务拒绝的问题
  • android的库不支持System V 的IPC
  • Binder加入了对象引用的引用计数器,消亡提醒机制。当一个Binder服务没有任何终端引用时,它的所有者可以自动提醒它去处理自己
  • Binder通过UID/PID来分辨发送者和接受者(对于安全很重要)

但是:

  • Binder不支持RPC,只有本地
  • 客户端和服务端基于消息通信,不适用于流
  • 不符合POSIX标准

1.2 binder通信流程

客户端使用服务

【Android】由浅到深理解AIDL_第1张图片

进程之间无法进行直接通信,所以通过Binder驱动

客户端和服务端不需要了解binder协议,所以使用代理和存根

客户端不想要知道正在使用IPC,也不关心binder和代理,所以,需要管理对象进行抽象
【Android】由浅到深理解AIDL_第2张图片

但是客户端怎样获取它想要通信的服务的handle,只需要问问sevicemanager(Context Manager),服务是否已经注册
【Android】由浅到深理解AIDL_第3张图片

最后,我们看下总体的架构

【Android】由浅到深理解AIDL_第4张图片

二 、 AIDL示例


使用aidl实现跨进程的加减法

2.1 服务端

新建android工程,创建包com.realize.calc.aidl,新建文件ICalcAIDL.aidl,内容如下

package com.realize.calc.aidl;interface ICalcAIDL{int add(int x , int y);int min(int x , int y );}

创建包com.realize.lizijun.binder_server,新建服务CalcService.java,内容如下

package com.realize.lizijun.binder_server; import com.realize.calc.aidl.ICalcAIDL; import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log; public class CalcService extends Service{private static final String TAG = "server"; public void onCreate(){Log.e(TAG, "onCreate");} public IBinder onBind(Intent t){Log.e(TAG, "onBind");return mBinder;} public void onDestroy(){Log.e(TAG, "onDestroy");super.onDestroy();} public boolean onUnbind(Intent intent){Log.e(TAG, "onUnbind");return super.onUnbind(intent);} public void onRebind(Intent intent){Log.e(TAG, "onRebind");super.onRebind(intent);} private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub(){ @Overridepublic int add(int x, int y) throws RemoteException{return x + y;} @Overridepublic int min(int x, int y) throws RemoteException{return x - y;} }; }

AndroidManifest.xml中注册服务

        <service android:name="com.realize.lizijun.binder_server.CalcService" >            <intent-filter>                <action android:name="com.realize.calc.aidl" />                 <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </service>


2.2 客户端

新建android工程,创建包com.realize.calc.aidl,新建文件ICalcAIDL.aidl(与服务端是一样的),内容如下

package com.realize.calc.aidl;interface ICalcAIDL{int add(int x , int y);int min(int x , int y );}

主activity内容如下

package com.realize.lizijun.binder_client; import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Toast; import com.realize.calc.aidl.ICalcAIDL; public class MainActivity extends Activity{private static final String TAG = "client";private ICalcAIDL mCalcAidl; private ServiceConnection mServiceConn = new ServiceConnection(){@Overridepublic void onServiceDisconnected(ComponentName name){Log.e(TAG, "onServiceDisconnected");mCalcAidl = null;} @Overridepublic void onServiceConnected(ComponentName name, IBinder service){Log.e(TAG, "onServiceConnected");mCalcAidl = ICalcAIDL.Stub.asInterface(service);}}; @Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); } /** * 点击BindService按钮时调用 * @param view */public void bindService(View view){Intent intent = new Intent();intent.setAction("com.realize.calc.aidl");bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);}/** * 点击unBindService按钮时调用 * @param view */public void unbindService(View view){unbindService(mServiceConn);}/** * 点击12+12按钮时调用 * @param view */public void addInvoked(View view) throws Exception{ if (mCalcAidl != null){int addRes = mCalcAidl.add(12, 12);Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();} else{Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show(); } }/** * 点击50-12按钮时调用 * @param view */public void minInvoked(View view) throws Exception{ if (mCalcAidl != null){int addRes = mCalcAidl.min(50, 12);Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();} else{Toast.makeText(this, "服务器未绑定或被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show(); } } }

界面如下:



2.3 结果说明

  • 点击BindService之后,服务端执行了onCreate和onBind的方法, 客户端执行onServiceConnected方法
  • 然后点击12+12,50-12可以成功的调用服务端的代码并返回正确的结果
  • 再点击unBindService, Service调用了onUnbind和onDestory
  • 然后点击12+12,50-12,仍然能够看到正确的结果,说明客户端与服务端的连接仍然存在
  • 我们通过后台,把服务强制停止掉,可以看到调用了onServiceDisconnected方法,此时,再点击12+12,50-12,就获取不到结果了

三、 分析AIDL生成的接口代码


上面创建ICalcAIDL.aidl之后,在gen目录下回生成文件ICalcAIDL.java, 该文件实现了客户端和服务端的代理(proxy)和存根(stub)

【Android】由浅到深理解AIDL_第5张图片

3.1 服务端

服务端代码中调用ICalcAIDL.Stub

private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub(){ @Overridepublic int add(int x, int y) throws RemoteException{return x + y;} @Overridepublic int min(int x, int y) throws RemoteException{return x - y;} };

而在CalcService.java中,很明显Stub就是Binder的子类

public static abstract class Stub extends android.os.Binder implements com.realize.calc.aidl.ICalcAIDL

接着看看Stub下面的方法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_add:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = this.add(_arg0, _arg1);reply.writeNoException();reply.writeInt(_result);return true;}case TRANSACTION_min:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = this.min(_arg0, _arg1);reply.writeNoException();reply.writeInt(_result);return true;}}return super.onTransact(code, data, reply, flags);}服务端会根据客户端发送来的消息执行onTransact方法,该方法有四个参数code 是一个整形的唯一标识,用于区分执行哪个方法data 客户端传递过来的参数reply 服务器返回的值flags 标明是否有返回值,0为有(双向),1为没有(单向)


3.2 客户端

客户端代码中,调用了ICalcAIDL.Stub.asInterface

private ServiceConnection mServiceConn = new ServiceConnection(){@Overridepublic void onServiceDisconnected(ComponentName name){Log.e(TAG, "onServiceDisconnected");mCalcAidl = null;} @Overridepublic void onServiceConnected(ComponentName name, IBinder service){Log.e(TAG, "onServiceConnected");mCalcAidl = ICalcAIDL.Stub.asInterface(service);}};

而ICalcAIDL.java文件中,asInterface,最终是调用到Proxy

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

所以,我们看下Proxy的add方法

@Override public int add(int x, int y) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(x);_data.writeInt(y);mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);_reply.readException();_result = _reply.readInt();}finally {_reply.recycle();_data.recycle();}return _result;}声明了两个android.os.Parcel对象,_data用于传递数据,_replay用于接收返回的数据最后调用transact方法,与服务端进行通信


四、不依赖AIDL的示例


怎样不通过AIDL文件,实现跨进程通信呢,从上面的分析中,我们可以知道,不通过AIDL文件,实现跨进程通信,那么实际上,就是要实现自动生成的AIDL文件中的接口功能, 下面我们实现跨进程的乘除调用

4.1 服务端

创建工程,实现CalcService.java,代码如下

package com.realize.lizijun.noaidl_binder_server; import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.os.Parcel;import android.os.RemoteException;import android.util.Log; public class CalcService extends Service{private static final String DESCRIPTOR = "CalcService";private static final String TAG = "server"; public void onCreate(){Log.e(TAG, "onCreate");} @Overridepublic int onStartCommand(Intent intent, int flags, int startId){Log.e(TAG, "onStartCommand");return super.onStartCommand(intent, flags, startId);} public IBinder onBind(Intent t){Log.e(TAG, "onBind");return mBinder;} public void onDestroy(){Log.e(TAG, "onDestroy");super.onDestroy();} public boolean onUnbind(Intent intent){Log.e(TAG, "onUnbind");return super.onUnbind(intent);} public void onRebind(Intent intent){Log.e(TAG, "onRebind");super.onRebind(intent);} private MyBinder mBinder = new MyBinder(); private class MyBinder extends Binder{@Overrideprotected boolean onTransact(int code, Parcel data, Parcel reply,int flags) throws RemoteException{switch (code){case 0x110:{Log.e(TAG, "0x110");data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = _arg0 * _arg1;reply.writeNoException();reply.writeInt(_result);return true;}case 0x111:{Log.e(TAG, "0x111");data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = _arg0 / _arg1;reply.writeNoException();reply.writeInt(_result);return true;}}return super.onTransact(code, data, reply, flags);} }; }自定义了一个Binder子类,然后复写了其onTransact方法

AndroidManifest.xml中注册服务
        <service android:name="com.realize.lizijun.noaidl_binder_server.CalcService" >            <intent-filter>                <action android:name="com.realize.noaidl.calc" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </service>


4.2 客户端

创建工程,其主activity内容如下所示:

package com.realize.lizijun.noaidl_binder_client; import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.widget.Toast; public class MainActivity extends Activity{private static final String TAG = "client";private IBinder mPlusBinder = null;private ServiceConnection mServiceConnPlus = new ServiceConnection(){// 只有当servie异常退出时,系统才会调用onServiceDisconnected()@Overridepublic void onServiceDisconnected(ComponentName name){Log.e(TAG, "mServiceConnPlus onServiceDisconnected");mPlusBinder = null;} @Overridepublic void onServiceConnected(ComponentName name, IBinder service){ Log.e(TAG, " mServiceConnPlus onServiceConnected");mPlusBinder = service;}}; @Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); } public void bindService(View view){Intent intentPlus = new Intent();intentPlus.setAction("com.realize.noaidl.calc");boolean result = bindService(intentPlus, mServiceConnPlus,Context.BIND_AUTO_CREATE);Log.e(TAG, result + "");} public void unbindService(View view){if (mServiceConnPlus != null){Log.e(TAG, "unbindService");unbindService(mServiceConnPlus);//mServiceConnPlus = null;}} public void mulInvoked(View view){ if (mPlusBinder == null){Toast.makeText(this, "未连接服务端或服务端被异常杀死", Toast.LENGTH_SHORT).show();} else{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result = 0;try{_data.writeInterfaceToken("CalcService");_data.writeInt(50);_data.writeInt(12);mPlusBinder.transact(0x110, _data, _reply, 0);_reply.readException();_result = _reply.readInt();Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show(); } catch (RemoteException e){e.printStackTrace();} finally{_reply.recycle();_data.recycle();}} } public void divInvoked(View view){ if (mPlusBinder == null){Toast.makeText(this, "未连接服务端或服务端被异常杀死", Toast.LENGTH_SHORT).show();} else{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result = 0;try{_data.writeInterfaceToken("CalcService");_data.writeInt(36);_data.writeInt(12);mPlusBinder.transact(0x111, _data, _reply, 0);_reply.readException();_result = _reply.readInt();Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show(); } catch (RemoteException e){e.printStackTrace();} finally{_reply.recycle();_data.recycle();}} }}

界面如下:

【Android】由浅到深理解AIDL_第6张图片

五、 示例代码下载

aidl示例代码


更多相关文章

  1. 简单的Android ROM制作方法:创建刷机包 备份ROM
  2. Android原生Switch控件滑块thumb卡住问题的解决方法
  3. Android 静默安装和智能安装的实现方法
  4. Android中Handler的使用方法——在子线程中更新界面
  5. 多个Android客户端同步服务器端表中数据架构分析
  6. Android网络编程之通过Get方法实现
  7. Android客户端和php+mysql+apache搭建的服务器之间的简单交互
  8. Android客户端使用HttpClient发起web数据访问
  9. android控件的监听绑定方法

随机推荐

  1. 解决CAS机制中ABA问题的AtomicStampedRef
  2. Java基础系列:线程同步和线程池
  3. ConcurrentHashMap.computeIfAbsent 死循
  4. java多线程(6)sleep和wait的4大区别
  5. SSL 证书选择指南
  6. 一文带你理解java中的同步工具类CountDow
  7. 你应该要理解的java并发关键字volatile
  8. android通过服务实现消息推送
  9. 一个同步工具类CyclicBarrier的详解(干货
  10. java中一个重要的原子类AtomicInteger详