天天看點

關于推送push中notification的一點問題

         對于推送,一般的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來啟動通知(當點選通知欄的通知時候)即使你不明确的指定。

         以上就是遇到的問題以及解決方法,有不對之處歡迎指正。