先上一段代碼:
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之前就有,無法確認。