AIDL进行线程间通信,随着项目规模的扩大,如果有多个业务模块都需要使用AIDL进行进程间通信;
如果按照AIDL的实现方式,需要一个个来实现,创建多个Service。
但这样有个问题,Service不能无限制地增加,Service是系统组件之一,本身就是系统资源。
太多Service会使得我们地应用看起来很重量级。
我们需要减少Service的数量,将所有的AIDL放在同一个Service中去管理。
整个模式的工作机制是这样的:
每个业务模块创建自己的AIDL接口并实现此接口;
这个时候不同的业务模块之间是不能耦合的,所有实现的细节要单独开来;
然后向服务端提供自己的唯一标识和其对应的Binder对象;
对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口;
这个接口能够根据业务模块的特征,来返回相应的Binder对象给它们,不同的业务模块拿到所需的Binder对象后,就可以进行远程方法调用了。
Binder连接池的主要作用是将每个业务模块的Binder请求统一转发到远程Service中去执行;
从而避免了重复创建Service的过程;
====================================================
这里创建了两个工程,一个是客户端,一个是服务端;
先看下服务端代码:
Manifest代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.learnbinderpool_service"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" > <service android:name=".BinderPoolService" android:enabled="true" android:exported="true"> </service> </application> </manifest>
BinderPoolService代码:
package com.example.learnbinderpool_service; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class BinderPoolService extends Service { private static final String TAG = "BinderPoolService"; private Binder mBinderPool = new BinderPoolImpl(); public BinderPoolService() { } @Override public void onCreate(){ super.onCreate(); } @Override public IBinder onBind(Intent intent) { Log.d(TAG,"onBind"); return mBinderPool; } @Override public void onDestroy(){ super.onDestroy(); } }
接着是三个AIDL接口的实现
ComputeImpl.java
package com.example.learnbinderpool_service; import android.os.RemoteException; public class ComputeImpl extends ICompute.Stub { @Override public int add(int a, int b) throws RemoteException{ return a+b; } }
SecurityCenterImpl.java
package com.example.learnbinderpool_service; import android.os.RemoteException; //实现AIDL接口 public class SecurityCenterImpl extends ISecurityCenter.Stub{ private static final char SECRET_CODE = '^'; @Override public String encrypt(String content) throws RemoteException { char[] chars = content.toCharArray(); for(int i = 0; i<chars.length; i++){ chars[i] ^= SECRET_CODE; } return new String(chars); } @Override public String decrypt(String password) throws RemoteException{ return encrypt(password); } }
BinderPoolImpl.java
package com.example.learnbinderpool_service; import android.os.IBinder; import android.os.RemoteException; public class BinderPoolImpl extends IBinderPool.Stub { public static final int BINDER_NONE = -1; public static final int BINDER_COMPUTE = 0; public static final int BINDER_SECURITY_CENTER = 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; } default: break; } return binder; } }
AIDL接口声明:
// IBinderPool.aidl package com.example.learnbinderpool_service; // Declare any non-default types here with import statements interface IBinderPool { IBinder queryBinder(int binderCode); }
// ICompute.aidl package com.example.learnbinderpool_service; // Declare any non-default types here with import statements interface ICompute { int add(int a, int b); }
// ISecurityCenter.aidl package com.example.learnbinderpool_service; // Declare any non-default types here with import statements interface ISecurityCenter { String encrypt(String content); String decrypt(String password); }
================================================================
然后是客户端工程代码:
Manifest
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.learnbinderpool_client"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
BinderPool.java
package com.example.myclient; import com.example.myservice.IBinderPool; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import androidx.core.view.KeyEventDispatcher; import java.util.concurrent.CountDownLatch; public class BinderPool { private static final String TAG = "BinderPool"; public static final int BINDER_NONE = -1; public static final int BINDER_COMPUTE = 0; public static final int BINDER_SECURITY_CENTER = 1; private Context mContext; private IBinderPool mBinderPool; private static volatile BinderPool sInstance; private CountDownLatch mConnectionBinderPoolCountDownLatch; //线程同步工具 private static boolean isConnected = false; private String mpkgname; private String mclasaname; private BinderPool(Context context,String pkgname,String clasaname){ mContext = context.getApplicationContext(); mpkgname = pkgname; mclasaname = clasaname; connectBinderPoolService(pkgname,clasaname); //实例化BidnerPool时就尝试与服务进行连接; } public boolean getConnectStatus(){ return isConnected; } //单例模式 public static BinderPool getInstance(Context context,String pkgname,String clasaname){ if (sInstance == null){ synchronized (BinderPool.class){ if(sInstance == null){ sInstance = new BinderPool(context,pkgname,clasaname); } } } return sInstance; } //服务连接函数 private synchronized void connectBinderPoolService(String pkgname, String classname){ Log.d(TAG,"connectBinderPoolService"); mConnectionBinderPoolCountDownLatch = new CountDownLatch(1); //由于要启动指定的服务,这里面采用显示intent的方式 //通过指定完整的包名、类名,启动指定服务 //从Android5.0开始 隐式Intent绑定服务的方式已不能使用 Intent intent = new Intent(); ComponentName com = new ComponentName(pkgname,classname); intent.setComponent(com); mContext.bindService(intent,mBinderPoolConnection,Context.BIND_AUTO_CREATE); try{ mConnectionBinderPoolCountDownLatch.await(); }catch (InterruptedException e){ e.printStackTrace(); } } public synchronized void disconnectBinderPoolService() { Log.d(TAG,"disconnectBinderPoolService"); mConnectionBinderPoolCountDownLatch = new CountDownLatch(1); Intent service = new Intent(mContext,BinderPool.class); mContext.unbindService(mBinderPoolConnection); try{ mConnectionBinderPoolCountDownLatch.await(); }catch (InterruptedException e){ e.printStackTrace(); } } public IBinder queryBinder(int binderCode){ IBinder binder = null; try{ if(mBinderPool != null){ binder = mBinderPool.queryBinder(binderCode); } }catch (RemoteException e){ e.printStackTrace(); } return binder; } //注意这是在主线程中调用的,所以子线程进行connectBinderPoolService连接时,要等待主线程连接完毕; public ServiceConnection mBinderPoolConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG,"onServiceConnected"); isConnected = true; mBinderPool = IBinderPool.Stub.asInterface(service); //在拿到IBinder引用后,通过这个函数获取实例 try{ //设置死亡代理 mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0); }catch (RemoteException e){ e.printStackTrace(); } mConnectionBinderPoolCountDownLatch.countDown(); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG,"onServiceDisconnected"); isConnected = false; mConnectionBinderPoolCountDownLatch.countDown(); } }; //当Binder死亡时,会回调相应函数 private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient(){ @Override public void binderDied(){ Log.d(TAG,"binder died."); mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0); mBinderPool = null; connectBinderPoolService(mpkgname,mclasaname); //重新尝试连接 } }; }
MainActivity.java
package com.example.myclient; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; import com.example.myservice.ICompute; import com.example.myservice.ISecurityCenter; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private static final String TAG = "MainActivity"; private String pkgname = "com.example.myservice"; private String classname = "com.example.myservice.BinderPoolService"; ISecurityCenter mSecurityCenter; ICompute mCompute; BinderPool mBinderPool; Button btn_conn; Button btn_disconn; Button btn_compute; Button btn_encrypt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_compute = findViewById(R.id.compute); btn_encrypt = findViewById(R.id.encrypt); btn_conn = findViewById(R.id.conn); btn_disconn = findViewById(R.id.disconn); btn_compute.setOnClickListener(this); btn_encrypt.setOnClickListener(this); btn_conn.setOnClickListener(this); btn_disconn.setOnClickListener(this); Log.d(TAG,"onCreate"); } @Override public void onClick(View v){ switch (v.getId()){ case R.id.conn:{ Log.d(TAG,"onClick R.id.conn"); new Thread(new Runnable(){ @Override public void run(){ //新建一个线程来进行与Service连接 //实例化BinderPool时,就会尝试与服务进行连接 mBinderPool = BinderPool.getInstance(MainActivity.this,pkgname,classname); } }).start(); break; } case R.id.disconn:{ Log.d(TAG,"onClick R.id.disconn"); //todo break; } case R.id.compute:{ Log.d(TAG,"onClick R.id.compute"); visitICompute(); break; } case R.id.encrypt:{ Log.d(TAG,"onClick R.id.encrypt"); visitISecurityCenter(); break; } default: break; } } private void visitISecurityCenter(){ if(mBinderPool.getConnectStatus() && mSecurityCenter == null){ IBinder securityBinder = mBinderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER); mSecurityCenter = ISecurityCenter.Stub.asInterface(securityBinder); //获得bindery引用后,实例化对象 Log.d(TAG,"visit ISecurityCenter"); String msg = "helloworld-Android"; Log.d(TAG,"content: "+msg); try{ String password = mSecurityCenter.encrypt(msg); Toast.makeText(this,"encrypt: "+password, Toast.LENGTH_SHORT).show(); Log.d(TAG,"encrypt: "+password); }catch (RemoteException e){ e.printStackTrace(); } } } private void visitICompute(){ if(mBinderPool.getConnectStatus() && mCompute == null){ IBinder computeBinder = mBinderPool.queryBinder(BinderPool.BINDER_COMPUTE); mCompute = ICompute.Stub.asInterface(computeBinder); //获得bindery引用后,实例化对象 Log.d(TAG,"visit ICompute"); try{ int result = mCompute.add(3,5); Toast.makeText(this,"compute result: "+result, Toast.LENGTH_SHORT).show(); Log.d(TAG,"encrypt: "+result); }catch (RemoteException e){ e.printStackTrace(); } } } }
=====================================================
目前代码还有点问题,需要进一步调试
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class BinderPoolService extends Service {
private static final String TAG = "BinderPoolService";
private Binder mBinderPool = new BinderPoolImpl();
public BinderPoolService() {
}
@Override
public void onCreate(){
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"onBind");
return mBinderPool;
}
@Override
public void onDestroy(){
super.onDestroy();
}
}