2.在绑定时intent设置action与package:
Intent intent = new Intent();
intent.setAction("your action");
intent.setPackage("service app's package name");//设置service所在app的包名
activity.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
然后就可以顺利绑定aidl中的service了。
注:onServiceDisconnected是绑定后意外断连后的回调,一般进行重新绑定的操作。
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
//一般进行重新绑定的操作
}
};
在Android 4.4的ContextImpl源码中,能看到如果启动service的intent的component和package都为空并且版本大于KITKAT的时候只是报出一个警报,告诉开发者隐式声明intent去启动Service是不安全的.再往下看,丫的异常都写好了只是注释掉了,看来google早就想这么干了.
private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (true || getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
//IllegalArgumentException ex = new IllegalArgumentException(
// "Service Intent must be explicit: " + service);
//Log.e(TAG, "This will become an error", ex);
//throw ex;
}
}
}
果然在Android 5.0的源码中上面注释的代码已经不注释了,当targetSdkVersion版本大于LOLLIPOP直接异常抛出来,要求Service intent必须显式声明.所以如果开发的应用指定targetSdkVersion版本是小于LOLLIPOP的话还是按以前的方式给报个警报,这也就造成了如果没有做了完善的Android 5.0兼容就贸然把targetSdkVersion升到LOLLIPOP的话很有可能就会碰到这个问题.并且这个问题是很严重的,想象一下,你的app自升级的Service是隐式启动的,碰到这个问题后app就不能自升级了,这批用户有可能就一直停留在当前版本.会产生很致命的问题.
private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
throw ex;
} else {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
}
}
}
从源码中的逻辑来看的话,判断一个intent是不是显式声明的点就是component和package,只要这两个有一个生效就不算是隐式声明的,接下来继续分析一下Intent的源码,可以看到下面三种构造方式,设置action来声明Intent是没有构建component的,所以显式声明需要用到第一和第二种构造(还有带packagename或component的拷贝构造),或者后面设置package属性.
public Intent(Context packageContext, Class> cls) {
mComponent = new ComponentName(packageContext, cls);
}
public Intent(String action) {
setAction(action);
}
public Intent(String action, Uri uri,
Context packageContext, Class> cls) {
setAction(action);
mData = uri;
mComponent = new ComponentName(packageContext, cls);
}
public Intent setPackage(String packageName) {
if (packageName != null && mSelector != null) {
throw new IllegalArgumentException(
"Can't set package name when selector is already set");
}
mPackage = packageName;
return this;
}