Android bindservice绑定服务,并同步返回service对象的两个方法
先上一段代码:
private IDeviceService deviceService = null;
private ServiceConnection conn=null;
private synchronized void bindyourservice() { Intent intent = new Intent();intent.setPackage("servicepackagename");intent.setAction("serviceactionname");conn=new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) { deviceService = IDeviceService.Stub.asInterface(iBinder);}@Overridepublic void onServiceDisconnected(ComponentName componentName) {..................................... }};try {if (bindService(intent, mConn, Service.BIND_AUTO_CREATE)) {...............................} else {....................}} catch (SecurityException e) {.........................}}
这个是最早绑定服务的方式,bindService返回绑定服务状态,访问服务接口需在取到ServiceConnection连接后再访问,整个过程是异步的,而且就算开线程去绑定服务、加锁也没办法在一个方法里面返回这个service对象,原因是这个方法里面的实现:
/frameworks/base/core/java/android/app/ContextImpl.java
看下这个的代码:
public boolean bindService(Intent service, ServiceConnection conn, int flags) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,getUser());}@Overridepublic boolean bindService(Intent service, int flags, Executor executor, ServiceConnection conn) {return bindServiceCommon(service, conn, flags, null, null, executor, getUser());}@Overridepublic boolean bindIsolatedService(Intent service, int flags, String instanceName,Executor executor, ServiceConnection conn) {warnIfCallingFromSystemProcess();if (instanceName == null) {throw new NullPointerException("null instanceName");}return bindServiceCommon(service, conn, flags, instanceName, null, executor, getUser());}@Overridepublic boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,UserHandle user) {return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null, user);}/** @hide */@Overridepublic boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,Handler handler, UserHandle user) {if (handler == null) {throw new IllegalArgumentException("handler must not be null.");}return bindServiceCommon(service, conn, flags, null, handler, null, user);}.....................private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,String instanceName, Handler handler, Executor executor, UserHandle user) {....................
}
bindServiceCommon是个私有方法,里面又套了几层代码,太长,翻起来就是整个系统bindservice的流程了。
关键点,bindservice执行的时候接收的Handler是 mMainThread.getHandler(),这个是APP的主线程,也就是无论外部怎么折腾,这个是在主线程接收的。
在上面这段系统代码段里面,有两个方法是可以使用的:
//method 1
public boolean bindService(Intent service, int flags, Executor executor, ServiceConnection conn)
//method 2
/** @hide */
@Override
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,Handler handler, UserHandle user)
1、bindService
在bindService有一个传参executor,接收ServiceConnection放到了这个里面:
private boolean[] isBind = {false};
private CountDownLatch latch = new CountDownLatch(1);
private boolean bindyourservice(final Context context){if(deviceService==null){latch = new CountDownLatch(1);Executor executor= Executors.newSingleThreadExecutor();executor.execute(new Runnable() {@Overridepublic void run() {mConn=new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinderiBinder) {deviceService = IDeviceService.Stub.asInterface(iBinder);isBind[0] =true;latch.countDown();}@Overridepublic void onServiceDisconnected(ComponentName className) { isBind[0] =false;latch.countDown();}};Intent intent = new Intent();intent.setPackage("yourservicename");intent.setAction("yourserviceaction");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {boolean bind=bindService(intent, Context.BIND_AUTO_CREATE,executor,mConn);if(!bind){ isBind[0] =false;latch.countDown();}}}});if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { try {latch.await();} catch (InterruptedException e) {e.printStackTrace();} if(!isBind[0])return false;}else{ return false;}} return true;}
需要注意的是Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q,这个方法是android7.0及以后提供的。
2、bindServiceAsUser
也可以实现方法1的功能,只不过把接收对象换成了Handler ,bindServiceAsUser是系统隐藏方法,需通过反射方法使用,至于bindServiceAsUser是否早于android7.0之前就有,无法确认。