對于推送,一般的APP都會有這種功能,這是一種拉回使用者,使其重新用我們APP增強使用者粘性的一種方法,是以這也是一種很常見的功能。但是之前一直沒注意 ,是以也忽略了一些問題,最近正好碰到了,記錄下來,防止大家再次踩坑。
因為最近的業務場景的需要,一個使用者會在很短的時間内收到比較多的推送,但是在之前的應用中,其實這種業務場景不會那麼多的。但是現在出現了,也出現了兩個問題。那麼出現的問題是什麼呢?問題一:當收到多條推送時候,在通知欄裡面後面的會覆寫前面的。問題二:解決問題一後,點選了通知欄裡面的notification,我們會傳遞一些值到廣播接收器中,但是發現後面的值依然是會覆寫前面的值。
其實看了下代碼中,關于發送notification部分的代碼就隻有如下幾行:
//接收服務端發送過來的自定義消息 (伺服器裡面必須不能有其他設定,隻是設定EXTRA_MESSAGE就好,title、content等都不要)
private void processCustomMessage(Context context,String message){
final NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(context, PushIntentRecever.class);
PersonalMessageBean personalMessageBean = GsonUtils.getModel(message,PersonalMessageBean.class);
intent.putExtra(ConstantValue.PARCELABLE_DATA,personalMessageBean);
intent.setAction("xxx");//如果是以PendingIntent方式發送廣播,action必須設定對
//第四個參數如果不是FLAG_UPDATE_CURRENT,那麼傳遞的參數可能會收不到;如果第二個參數每次不是唯一的,那麼傳遞的參數會覆寫
PendingIntent pi = PendingIntent.getBroadcast(context, (int) System.currentTimeMillis(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
int defaults = 0;
defaults |= Notification.DEFAULT_SOUND;//系統提示音
defaults |= Notification.DEFAULT_VIBRATE;//系統震動
defaults |= Notification.DEFAULT_LIGHTS;//系統燈光
builder.setContentIntent(pi)
.setSmallIcon(R.mipmap.ic_launcher).setTicker(ResourcesUtil.getString(R.string.app_name)).setWhen(System.currentTimeMillis())
.setOnlyAlertOnce(true).setAutoCancel(true).setContentTitle(ResourcesUtil.getString(R.string.app_name))
.setContentText(personalMessageBean.getMessageContent()).setDefaults(defaults);
Notification notification = builder.build();
//第一個參數是消息的notification的id,如果相同的話,那麼通知就會覆寫啦
nm.notify((int) System.currentTimeMillis(), notification);
}
當然上面是我修改之後的代碼,其實關鍵的地方就在于我上面寫注釋的地方,解決問題一的關鍵在于NotificationManager的notify方法的第二個參數了。解決問題二關鍵就在于PendingIntent的getBroadcast方法的第二個參數。
那我們先看看notify方法的注釋:
/**
* Post a notification to be shown in the status bar. If a notification with
* the same id has already been posted by your application and has not yet been canceled, it
* will be replaced by the updated information.
*
* @param id An identifier for this notification unique within your
* application.
* @param notification A {@link Notification} object describing what to show the user. Must not
* be null.
*/
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
可以看到注釋寫的很清楚,會向狀态欄發送一個通知,如果我們自己應用已經發送了一個相同id的通知且沒有被取消,那麼之前的相同的id的notification就會被後面新發送的覆寫。這塊原來也是沒仔細看,既然想要唯一id,是以上面就直接放了個時間戳上去了,當然需要強轉成int類型的。
然後看第二個問題的解決方案,我們來看看getBroadcast方法的注釋:
/**
* Retrieve a PendingIntent that will perform a broadcast, like calling
* {@link Context#sendBroadcast(Intent) Context.sendBroadcast()}.
*
* <p class="note">For security reasons, the {@link android.content.Intent}
* you supply here should almost always be an <em>explicit intent</em>,
* that is specify an explicit component to be delivered to through
* {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
*
* @param context The Context in which this PendingIntent should perform
* the broadcast.
* @param requestCode Private request code for the sender
* @param intent The Intent to be broadcast.
* @param flags May be {@link #FLAG_ONE_SHOT}, {@link #FLAG_NO_CREATE},
* {@link #FLAG_CANCEL_CURRENT}, {@link #FLAG_UPDATE_CURRENT},
* {@link #FLAG_IMMUTABLE} or any of the flags as supported by
* {@link Intent#fillIn Intent.fillIn()} to control which unspecified parts
* of the intent that can be supplied when the actual send happens.
*
* @return Returns an existing or new PendingIntent matching the given
* parameters. May return null only if {@link #FLAG_NO_CREATE} has been
* supplied.
*/
public static PendingIntent getBroadcast(Context context, int requestCode,
Intent intent, @Flags int flags) {
return getBroadcastAsUser(context, requestCode, intent, flags,
new UserHandle(UserHandle.myUserId()));
}
哇,這個注釋還是蠻多的。大緻意思就是 擷取生成一個PendingIntent,就會發送一個廣播,就像調用了Context.sendBroadcast()方法一樣子,下面說 為了安全考慮,這個方法的第三個參數intent,最好是使用顯示的方式,就是使用setClass的方式聲明出意向類,最好不要使用隐式意圖,而我上面竟然是用的隐示意圖(捂臉笑表情一個);第一個參數context就是要發送廣播的上下文對象了,第二個參數requestCode,這個就是對于發送者的請求code,有點類似于我們startActivityForResult時候傳遞的requestCode了,是以說如果這個requestcode的值所有notification都一樣,那麼就會被認為是同一個意圖,自然extra資料是會被覆寫的。第三個參數剛說過了,第四個參數也是蠻重要的,意思大概是說這個參數會控制當實際的發送notification發生時候可以提供哪些我們未指定的intent,應該就是intent攜帶的資料了;通過看注釋我們發現FLAG_UPDATE_CURRENT比較适合我們的業務場景:
/**
* Flag indicating that if the described PendingIntent already exists,
* then keep it but replace its extra data with what is in this new
* Intent. For use with {@link #getActivity}, {@link #getBroadcast}, and
* {@link #getService}. <p>This can be used if you are creating intents where only the
* extras change, and don't care that any entities that received your
* previous PendingIntent will be able to launch it with your new
* extras even if they are not explicitly given to it.
*/
public static final int FLAG_UPDATE_CURRENT = 1<<27;
它的大緻意思是如果描述的PendingIntent已經存在,然後會保持它,但是也會用新的intent的extra替換老的extra data;這種方式可以用于如果你建立了一個隻有extras發生變化的intent并且不在意之前的PendingIntent所收到的實體,是以它将會用新的extra來啟動通知(當點選通知欄的通知時候)即使你不明确的指定。
以上就是遇到的問題以及解決方法,有不對之處歡迎指正。