先上一段代码:
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() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
deviceService = IDeviceService.Stub.asInterface(iBinder);
}
@Override
public 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());
}
@Override
public boolean bindService(
Intent service, int flags, Executor executor, ServiceConnection conn) {
return bindServiceCommon(service, conn, flags, null, null, executor, getUser());
}
@Override
public 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());
}
@Override
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null, user);
}
/** @hide */
@Override
public 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() {
@Override
public void run() {
mConn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder
iBinder) {
deviceService = IDeviceService.Stub.asInterface(iBinder);
isBind[0] =true;
latch.countDown();
}
@Override
public 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之前就有,无法确认。