Broadcast的Intent中塞入INTENT_NEW_TASK引發的兼容性問題


0. 起源

在做通知欄時,因為需要做點擊通知欄做一些非啟動Activity的操作,因此需要通過如下代碼接受點擊通知欄事件的廣播

Intent clickIntent = new ntent(mContext,NotificationClickReceiver.class);
PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, STOP_NOTIFICATION_ID,clickIntent,PendingIntent.FLAG_CANCEL_CURRENT);
mNotificationBuilder.setContentIntent(contentIntent); I

這樣的代碼本身是沒有問題的,但是因為在htc的某個rom下會出現在kill掉app后,通過startForeground啟動的通知欄在點擊的時候,無法正常接受和發送廣播(原因是因為點擊后會重新啟動一個新的進程運行應用)。

具體點擊跳轉到stack-overflow查看.

因此需要在clickIntent中加入

clickIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_NEW_TASK);

1. 引發的問題

在4.4以下的機子下會出現crash,日志如下

java.lang.RuntimeException:Unable to start service com.flamingo.gpgame.service.GPDownloadService@4197e5e0 with Intent { cmp=com.flamingo.gpgame/.service.GPDownloadService (has extras) }: java.lang.IllegalArgumentException: Can't use FLAG_RECEIVER_BOOT_UPGRADE here

具體就是因為發送的廣播Intent不能有FLAG_RECEIVER_BOOT_UPGRADE這個flags,我們的app不具備這種flags廣播發送的權限。

2. 原因探尋

在我們的Intent中其實並沒有添加FLAG_RECEIVER_BOOT_UPGRADE這個flag,只是添加了Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_NEW_TASK這三種flag,通過搜索資料發現,原來是因為谷歌工程師粗心大意把Intent.FLAG_ACTIVITY_NEW_TASKIntent. FLAG_RECEIVER_BOOT_UPGRADE的常量混淆了,系統就誤認為我們發送了Intent. FLAG_RECEIVER_BOOT_UPGRADE這個廣播。

具體點擊跳轉到stack-overflow查看.

通過分析源碼也驗證這上面的說法,在android-15的源碼中

   /**
* <strong>Do not use this flag unless you are implementing your own
* top-level application launcher.</strong> Used in conjunction with
* {@link #FLAG_ACTIVITY_NEW_TASK} to disable the
* behavior of bringing an existing task to the foreground. When set,
* a new task is <em>always</em> started to host the Activity for the
* Intent, regardless of whether there is already an existing task running
* the same thing.
*
* <p><strong>Because the default system does not include graphical task management,
* you should not use this flag unless you provide some way for a user to
* return back to the tasks you have launched.</strong>
*
* <p>This flag is ignored if
* {@link #FLAG_ACTIVITY_NEW_TASK} is not set.
*
* <p>See
* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
* Stack</a> for more information about tasks.
*/

public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000;

public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x08000000;

發現FLAG_ACTIVITY_MULTIPLE_TASKFLAG_RECEIVER_BOOT_UPGRADE的常量值是一致的,而注釋中也提到FLAG_ACTIVITY_NEW_TASK是會覆蓋FLAG_ACTIVITY_MULTIPLE_TASK的值,因此可以猜想處理中應該是FLAG_ACTIVITY_NEW_TASK包含了FLAG_ACTIVITY_MULTIPLE_TASK,系統也會認為賦值了FLAG_ACTIVITY_NEW_TASK的flags會擁有FLAG_RECEIVER_BOOT_UPGRADE的屬性。

上述stack-overflow提到在android-19以后的版本修復了這個問題,查看源碼發現確實是這樣的,常量已經改變了值,以防沖突。

public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;

3.解決方式

因為在實際應用中既要解決htc那個rom的奇葩問題,又要保證Android 4.4以下的機子正常運行,只能通過版本判斷來區分是否添加flag(幸好Htc的rom是基於Android 4.4)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
clickIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
}

當然,保險的方法是在平時的使用中不要在廣播的Intent中添加Intent.FLAG_ACTIVITY_NEW_TASK,最保險的就是連Intent.FLAG_ACTIVITY_XX的值都不要添加。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com