爲什麼點擊推送通知打不開Activity?Calling startActivity() from outside……

小米推送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

img1
我不想要我調你方法幹嗎。

解決

解決就不說了,報錯提示擺明了,要我傳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

相關文章
相關標籤/搜索