《Android开发艺术与探索》读书笔记之Binder

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010221508/article/details/88080965

1.Binder是Android中夸进程通信的一种方式。从Android FrameWork 角度来说,Binder是ServiceManager连接各种Manager(ActivityManager和WindowManager等)和相应ManagerService的桥梁。从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回包含了一个服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据。

2.Binder原理解析:
当客户端发起跨进程请求的时候,远程请求经过系统底层封装交由aidl文件自动生成的java文件中的onTransact(int code,android.os.Parcel data,android.os.Parcel reply,int flag)方法处理,服务器通过code来确定客户端所请求的目标方法是什么,接着从data中取出目标方法所需的参数,然后执行目标方法,当目标方法执行完毕后,就向reply中写入返回值。

客户端则是通过调用Proxy里面的相应的方法来执行请求的,接着再调用transact()方法来发起远程请求,同时当前线程挂起,然后服务端的onTranact方法会被调用,返回_reply,当前线程继续执行,并且从_reply中取出调用返回的结果。

//这个就是onTranact方法,通过这个方法调用服务器里面具体的方法,执行相应的逻辑
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
//通过code来识别客户端到底调用的是服务器的那个方法
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
//如果code是TRANSACTION_encrypt,则调用的是encrypt(String content)方法
case TRANSACTION_encrypt:
{
data.enforceInterface(descriptor);
java.lang.String _arg0;
//从data中取出客户端传过来的数据,作为方法得参数(如果所调用方法需要参数的话)
_arg0 = data.readString();
//执行方法得调用,并返回调用结果
java.lang.String _result = this.encrypt(_arg0);
reply.writeNoException();
//把调用结果写入到reply中
reply.writeString(_result);
return true;
}
...
//客户端aidl代理对象,通过这个代理对象,执行aidl中的方法
private static class Proxy implements com.imoran.auto.aidldemo.ISecurityCenter
{
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;
}
//调用encrypt方法,
@Override public java.lang.String encrypt(java.lang.String content) 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(content);
//调用tranact方法,发起远程通信,_data里面保存了客户端要向服务器传的参数,_reply是用来让服务器存储方法返回数据的
mRemote.transact(Stub.TRANSACTION_encrypt, _data, _reply, 0);
_reply.readException();
//方法执行完成之后,从_reply中读取远程服务器方法返回的数据
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...

在这里插入图片描述
注意事项:首先,当客户端发起请求的时候,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么在此UI线程中不能发起此远程请求。
其次,由于服务端的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时,都应该采用同步的方法去实现

3.Binder主要用于和Service的跨进程通信中,Binder使用方式如下:

创建服务器端工程

(1). 创建工程
在这里插入图片描述在这里插入图片描述
(2). 创建AIDL文件
在这里插入图片描述
ICompute.aidl 主要实现的功能是两个int数相加

	interface ICompute {

    	int add(int a,int b);
	}
	
ISecurityCenter.aidl  主要模拟对数据加密解密功能(只是演示)

	interface ISecurityCenter {
		//加密
   	String encrypt(String content);
		//解密
    	String decrypt(String password);
	}

IBinderPool.aidl   主要实现根据客户端需要是获取ISecurityCenter的binder对象还是ICompute的binder对象

	interface IBinderPool {
    	IBinder queryBinder(int binderCode);
	}

(3). 编译工程,会自动生成对应的java文件
在这里插入图片描述
(4). 实现对应的接口
在这里插入图片描述

	public class ComputeImpl extends ICompute.Stub {
	    @Override
	    public int add(int a, int b) throws RemoteException {
	        return a + b;
	    }
	}


	public class SecurityCenterImpl extends ISecurityCenter.Stub {

	    @Override
	    public String encrypt(String content) throws RemoteException {
	        return content + "加密";
	    }
	
	    @Override
	    public String decrypt(String password) throws RemoteException {
	        return password + "解密";
	    }
	}


	public class BindPoolImpl extends IBinderPool.Stub {

	    private final int BINDER_SECURITY_CENTER = 0;
	    private final int BINDER_COMPUTE = 1;
	
	    @Override
	    public IBinder queryBinder(int binderCode) throws RemoteException {
	        IBinder binder = null;
	        switch (binderCode) {
	            case BINDER_SECURITY_CENTER: {
	                binder = new SecurityCenterImpl();
	                break;
	            }
	            case BINDER_COMPUTE:{
	                binder = new ComputeImpl();
	                break;
	            }
	        }
	        return binder;
	    }
	}

实现类逻辑比较简单,就不再分析了

(5). 创建Service,在onBind方法中返回IBinder对象

	public class BinderPoolService extends Service {
	    private Binder mBinderPool = new BindPoolImpl();
	
	    @Override
	    public void onCreate() {
	        super.onCreate();
	    }
	
	    @Override
	    public IBinder onBind(Intent intent) {
	        return mBinderPool;
	    }
	
	    @Override
	    public void onDestroy() {
	        super.onDestroy();
	
	    }
	}

(6). 在清单文件AndroidManifest.xml中配置Service

	 <service android:name=".server.BinderPoolService"
        android:exported= "true"/>

其中exported这个属性表示其他应用组件是否可以唤醒service或者和这个service交互:true表示可以,false表示不可以。如果为false,只有同一个应用的组件或者具有同样userID的应用可以启动这个service或者绑定这个service

以上是服务器端的操作步骤,下面是客户端的操作步骤

创建客户端工程

(1). 创建工程
在这里插入图片描述
(2). 把服务器端创建的aidl文件拷贝到客户端(注意客户端aidl文件的目录结构要和服务器端一样)
在这里插入图片描述
(3). 编译工程,aidl文件自动生成java文件
在这里插入图片描述
(4).创建服务器管理类,主要功能是调起服务,获取服务器返回的IBinder对象,调用远程服务提供的功能
在这里插入图片描述

	public class BinderPool {
	    public static final String NAME_AIDL_REMOTE_SERVICE = "com.imoran.auto.myapplication.server.BinderPoolService";
	    public static final String PACKAGE_AIDL_REMOTE_SERVICE = "com.imoran.auto.myapplication";
	    private Context mContext;
	    private IBinderPool mBinderPool;
	    private static volatile BinderPool sInstance;
	    private CountDownLatch mConnectBinderPoolCountDownLatch;

    private BinderPool(Context context) {
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }
    
	    //调起远程service
	    private void connectBinderPoolService() {
	        mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
	        ComponentName componentName = new ComponentName(PACKAGE_AIDL_REMOTE_SERVICE,
	                NAME_AIDL_REMOTE_SERVICE);
	        Intent intent = new Intent();
	        intent.setComponent(componentName);
	        mContext.bindService(intent,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
	        try {
	            mConnectBinderPoolCountDownLatch.await();
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }
	    }
	    
	    //根据服务端BindPool对象,获取对应的其他Binder对象
	    public IBinder queryBinder(int binderCode) {
	        IBinder binder = null;
	        try {
	            if (binder == null) {
	                binder = mBinderPool.queryBinder(binderCode);
	            }
	        } catch (RemoteException e) {
	            e.printStackTrace();
	        }
	        return binder;
	    }
	    
	    //获取服务端BindPool对象
	    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
	        @Override
	        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
	            mBinderPool = IBinderPool.Stub.asInterface(iBinder);
	            try {
	                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
	            } catch (RemoteException e) {
	                e.printStackTrace();
	            }
	            mConnectBinderPoolCountDownLatch.countDown();
	        }
	
	        @Override
	        public void onServiceDisconnected(ComponentName componentName) {
	
	        }
	    };
	    
	    //死亡代理,当服务与客户端断开了的时候,重新连接
	    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
	        @Override
	        public void binderDied() {
	            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
	            mBinderPool = null;
	            connectBinderPoolService();
	        }
	    };
	
	    public static BinderPool getsInstance(Context context) {
	        if (sInstance == null) {
	            synchronized (BinderPool.class) {
	                if (sInstance == null) {
	                    sInstance = new BinderPool(context);
	                }
	            }
	        }
	        return sInstance;
	    }
	}
(5). 在Activity里面获取到对应的Binder对象执行具体功能

		public void dowork(View view) {
	        new Thread(new Runnable() {
	            @Override
	            public void run() {
	                doWork();
	            }
	        }).start();
	    }
	
	    private void doWork() {
	        BinderPool binderPool = BinderPool.getsInstance(this);
	        IBinder binder = binderPool.queryBinder(0);
	        IBinder computeBinder = binderPool.queryBinder(1);
	        ISecurityCenter iSecurityCenter = ISecurityCenter.Stub.asInterface(binder);
	        try {
	            String password = iSecurityCenter.encrypt("Hello Andorid");
	            Log.e("TAG",password);
	            Log.e("TAG",iSecurityCenter.decrypt(password));
	        } catch (RemoteException e) {
	            e.printStackTrace();
	        }
	
	        ICompute iCompute = ICompute.Stub.asInterface(computeBinder);
	        try {
	            Log.e("TAG",iCompute.add(3,6) + "result");
	        } catch (RemoteException e) {
	            e.printStackTrace();
	        }
	    }	

客户端和服务器端demo源码地址:
客户端:https://gitee.com/ABC_MA_NONG/AIDL_client.git
服务器端:https://gitee.com/ABC_MA_NONG/AIDL_serve.git

猜你喜欢

转载自blog.csdn.net/u010221508/article/details/88080965
今日推荐