一、需求
开发过程中,经常有应用间界面跳转需求,这里建议使用隐士Activity跳转,因为显示跳转需提供类名,哪天别人维护的时候把名字改了,那就爽歪歪了。
二、跳转代码
自己应用AndroidManifest.xml中注册启动action:com.jane.test.START
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.jane.test.START" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
其他应用启动代码:
private static final String ACTION = "com.jane.test.START";
private void startActivityWithAction(String action) {
try {
Intent intent = new Intent();
intent.setAction(action);
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}
三、遇到问题
1、注册action的时候Intent filter没有添加android.intent.category.DEFAULT导致启动失败,原因如下:
Android treats all implicit intents passed to startActivity() as if they contained at least one category: “android.intent.category.DEFAULT” (the CATEGORY_DEFAULT constant). Therefore, activities that are willing to receive implicit intents must include “android.intent.category.DEFAULT” in their intent filters。
每一个通过 startActivity() 方法发出的隐式 Intent 都至少有一个 category,就是 “android.intent.category.DEFAULT”,所以只要是想接收一个隐式 Intent 的 Activity 都应该包括 “android.intent.category.DEFAULT” category,不然将导致 Intent 匹配失败。
2、后台service未加FLAG_ACTIVITY_NEW_TASK flag启动Activity启动失败,原因是在启动的源码逻辑加了该flag判断:
android-23 中startActivity##
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
android-26 中startActivity##
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
看参考文章2分析,在android 24-android 27(即android N-android O)判断条件options != null一直是false,也就是说即使没有加Intent.FLAG_ACTIVITY_NEW_TASK也会正常跳转。
但是为了兼容所有平台,启动时统一加入该flag,修改代码如下:
private static final String ACTION = "com.jane.test.START";
private void startActivityWithAction(String action) {
try {
Intent intent = new Intent();
intent.setAction(action);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}
3、Android版本10以上只能启动一次(这个我没碰到,查找的时候看到的,先记录下),由于10更新后的安全机制,解决方法;
(1)申请SYSTEM_ALERT_WINDOW悬浮窗权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
(2)非系统应用需要动态请求下权限。
if (!Settings.canDrawOverlays(this)) {
//若未授权则请求权限
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 0);
}
参考文档:
隐式启动Activity,Intent filter必须添加android.intent.category.DEFAULT
Android Service启动Activity
Android中通过Service启动Activity遇到的问题及解决方案
Android Notification、PendingIntent与后台启动Service、Activity浅析