小米推送Android SDK有這麼一個耳熟能詳的方法:java
/** * 接收服務器向客戶端發送的通知消息,在用戶手動點擊通知後觸發 */
public void onNotificationMessageClicked(Context context, MiPushMessage message) {
...
context.startActivity(intent);
}
複製代碼
若是在其中手動增長啓動Activity的邏輯,會發現,點了沒反應。把 startActivity
方法try-catch後,發現這麼一個異常:android
Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?服務器
解讀一下就是,說我要是從外面啓動本應用的Activity須要傳 FLAG_ACTIVITY_NEW_TASK
標識,還特別嘲諷地反問我一句:這真是你想要的? app
解決就不說了,報錯提示擺明了,要我傳NEW_TASK,是的,就這麼簡單。框架
public void onNotificationMessageClicked(Context context, MiPushMessage message) {
...
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
複製代碼
這異常究竟是什麼意思?找找系統源碼(基於Android P源碼): frameworks/base/core/java/android/app/ContextImpl.java
在此類中,大概900多行的位置:ide
...
@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. A bug was existed between N and O-MR1 which allowed this to work. We
// maintain this for backwards compatibility.
final int targetSdkVersion = getApplicationInfo().targetSdkVersion;
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& (targetSdkVersion < Build.VERSION_CODES.N
|| targetSdkVersion >= Build.VERSION_CODES.P)
&& (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);
}
...
複製代碼
從這段長註釋能夠看出: 一、並非必定要帶NEW_TASK,若是指定了任務棧,也沒問題,這一點從判斷邏輯中的 ActivityOptions.fromBundle(options).getLaunchTaskId() == -1
便可看出; 二、居然這個異常在Android N到O上不會拋出,且谷歌指明這是一個Bug,只是爲了兼容,保留了這個判斷:targetSdkVersion < Build.VERSION_CODES.N || targetSdkVersion >= Build.VERSION_CODES.P
,所以對於targetSDK小於N或大於等於P的應用,就會正常地拋出此異常。ui
回到最開始的推送click回調中,其中傳入的context自己不屬於Activity,而是ApplicationContext,因此無法啓動另外一個Activity,系統不知道它應該屬於哪一個任務棧,因此須要你指定,無論是經過NEW_TASK的方式仍是Activity的 android:taskAffinity
屬性。 再看,小米推送發通知的操做是系統推送服務框架執行的,服務框架自己不具備Activity組件,也沒有任務棧,因此啓動另外一個Activity不指定task的話那按理來講就是不能。 那爲何在targetSDK在N到O之間就能夠呢?谷歌說的Bug現象是什麼呢?能夠推理,不指定任務棧還強制啓動一個Activity,那麼該遊離Activity雖然能夠啓動,但在最近任務列表裏看不見;或者說系統爲其指定了默認的task,當再從桌面正常啓動應用時,最近任務就會出現兩個MainActivity這種相似現象。this