Zenogrammer
Zenogrammer

Reputation: 813

Generate int unique id as android notification id

When I send multiple push notifications, I need them to be all shown in the notification bar ordered by the time sent desc. I know I should use unique notification - I tried to generate random number but that did not solve my problem since I need them to be ordered. I tried to use AtomicInt and still don't have the desired result.

package com.mypackage.lebadagency;
import java.util.concurrent.atomic.AtomicInteger;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.NotificationCompat;
import android.util.Log;



import android.widget.RemoteViews;

import com.google.android.gms.gcm.GoogleCloudMessaging;

public class GCMNotificationIntentService extends IntentService {

  private AtomicInteger c = new AtomicInteger(0);
  public int NOTIFICATION_ID = c.incrementAndGet(); 

  private NotificationManager mNotificationManager;
  NotificationCompat.Builder builder;

  public GCMNotificationIntentService() {
    super("GcmIntentService");
  }

  public static final String TAG = "GCMNotificationIntentService";

  @Override
  protected void onHandleIntent(Intent intent) {
    Bundle extras = intent.getExtras();
    GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);

    String messageType = gcm.getMessageType(intent);

    if (!extras.isEmpty()) {
      if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
          .equals(messageType)) {
        sendNotification("Send error: " + extras.toString());
      } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
          .equals(messageType)) {
        sendNotification("Deleted messages on server: "
            + extras.toString());
      } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
          .equals(messageType)) {

        for (int i = 0; i < 3; i++) {
          Log.i(TAG,
              "Working... " + (i + 1) + "/5 @ "
                  + SystemClock.elapsedRealtime());
          try {
            Thread.sleep(5000);
          } catch (InterruptedException e) {
          }

        }
        Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());

        sendNotification(""
            + extras.get(Config.MESSAGE_KEY));
        Log.i(TAG, "Received: " + extras.toString());
      }
    }
    GcmBroadcastReceiver.completeWakefulIntent(intent);
  }

  private void sendNotification(String msg) {

    Log.d(TAG, "Preparing to send notification...: " + msg);
    mNotificationManager = (NotificationManager) this
        .getSystemService(Context.NOTIFICATION_SERVICE);
    //here start
    Intent gcmintent = new Intent(this, AppGcmStation.class);
    gcmintent.putExtra("ntitle", msg);
    gcmintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    int requestID = (int) System.currentTimeMillis();
    //here end
    PendingIntent contentIntent = PendingIntent.getActivity(this, requestID,
        gcmintent, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
        this).setSmallIcon(R.drawable.ic_launcher)
        .setContentTitle("my title")
        .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
        .setContentText(msg);
    mBuilder.setAutoCancel(true);
    mBuilder.setTicker(msg);
    mBuilder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 }); 
    mBuilder.setLights(Color.RED, 3000, 3000);
    mBuilder.setContentIntent(contentIntent);
    mBuilder.setDefaults(Notification.DEFAULT_SOUND);



    mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    Log.d(TAG, "Notification sent successfully.");
  }
}

I need the BEST and simplest way to generate an int id which is incremental to assign it as the notification id.

Upvotes: 81

Views: 71515

Answers (8)

Alexandre Bianchi
Alexandre Bianchi

Reputation: 334

I'm using a simple way here.

Just use the method notify from NotificationManager with parameter tag. You will use tag to count only the notifications with tags that you create. Use a tag of your choice. The base method is below.

public void notify(String tag, int id, Notification notification) {
    notifyAsUser(tag, id, notification, mContext.getUser()); 
}

We will use the version with tag because if you send 1 or more notifications, Android can generate other notification with tag ranker_group and you will count it if you use it without tag parameter.

To get the next notificationId, use the method below:

private fun getNextNotificationId(): Int {
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val activeNotifications =
        notificationManager.activeNotifications
            .filter { it.tag == packageName }
    return if (activeNotifications.isEmpty()) {
        0
    } else {
        Collections.max(activeNotifications.map { it.id }) + 1
    }
}
  • In the above code, you will go through all active notifications with tag of your choice. Here I use packageName, the context variable that returns the package of the app.
  • If you don't have any notification, it will start with indice 0.
  • If you have 1 or more notifications, get the max notification id with Collections.max inside the map of all notification ids. When you have the maximum existent id, increment 1 to get the next notification id to use in your notification.

Ready!

Upvotes: 0

ImBatman
ImBatman

Reputation: 366

You need to set either a unique tag (String) / id (integer)

Checkout this method in official documentaation

I suggest using any timestamp (SystemClock.uptimeMillis() / System.currentTimeMillis()) as a tag while notifying.

 notificationManager.notify(String.valueOf(System.currentTimeMillis()), 0, notification);

Upvotes: 5

Agent_L
Agent_L

Reputation: 5421

Maybe not the best, but definitely the simplest is to use current time.

int oneTimeID = (int) SystemClock.uptimeMillis();
mNotificationManager.notify(oneTimeID, mBuilder.build());

The good: this is the easiest way to get increasing ids.

The bad: time is a long and we're truncating it to half of that. This means that the counter will wrap around every 2'147'483'647 /1000(ms->s)/60(s->m)/60(m->h)/24(h->d) =~25 days.

SystemClock.uptimeMillis() has 2 advantages over currentTimeMillis:

  1. discounts all the milliseconds spent at deep sleep, what decreases amount of wraparounds.
  2. starts at 0 when the phone is restarted.

Upvotes: 24

Chuy47
Chuy47

Reputation: 2417

You can use a counter and store it in the SharedPreferences. This is an example in kotlin:

fun getNextNotificationId(context: Context) : Int {
    val sp = context.getSharedPreferences("your_shared_preferences_key", MODE_PRIVATE)
    val id = sp.getInt("notification_id_key", 0)
    sp.edit().putInt("notification_id_key", (id + 1) % Int.MAX_VALUE).apply()

    return id
}

it will get the id and it will store the next id (increased by 1), also if the id reaches the max value for an integer it will be reset to 0.

You can use it like this:

val notificationId = getNextNotificationId(applicationContext)
notificationManager.notify(notificationId, yourNotification)

Upvotes: 5

Renjith Thankachan
Renjith Thankachan

Reputation: 4336

If someone reading this, there is a method here. it is better to specify a tag name also with id, so that it will help if you are bundling the part as a module to share with developers.

NOTE: The problem with assigning some random integer id is that, if any module or library uses the same id, your notification will be replaced by new notification data.

// here createID method means any generic method of creating an integer id
int id = createID();
// it will uniqly identify your module with uniq tag name & update if present.
mNotifyManager.notify("com.packagename.app", id, mBuilder.build());

Upvotes: 1

Raphael C
Raphael C

Reputation: 2402

private static final String PREFERENCE_LAST_NOTIF_ID = "PREFERENCE_LAST_NOTIF_ID";

private static int getNextNotifId(Context context) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    int id = sharedPreferences.getInt(PREFERENCE_LAST_NOTIF_ID, 0) + 1;
    if (id == Integer.MAX_VALUE) { id = 0; } // isn't this over kill ??? hahaha!!  ^_^
    sharedPreferences.edit().putInt(PREFERENCE_LAST_NOTIF_ID, id).apply();
    return id;
}

Upvotes: 18

Adetunji Mohammed
Adetunji Mohammed

Reputation: 674

For anyone still looking around. I generated a timestamp and used it as the id.

import java.util.Date;
import java.util.Locale;

public int createID(){
   Date now = new Date();
   int id = Integer.parseInt(new SimpleDateFormat("ddHHmmss",  Locale.US).format(now));
   return id;
}

Use it like so

int id = createID();
mNotifyManager.notify(id, mBuilder.build());

Upvotes: 38

Ted Hopp
Ted Hopp

Reputation: 234807

You are using the same notification ID (the value is always 1) for all your notifications. You probably should separate out the notification ID into a separate singleton class:

public class NotificationID {
    private final static AtomicInteger c = new AtomicInteger(0);
    public static int getID() {
        return c.incrementAndGet();
    }
}

Then use NotificationID.getID() instead of NOTIFICATION_ID in your code.

EDIT: As @racs points out in a comment, the above approach is not enough to ensure proper behavior if your app process happens to be killed. At a minimum, the initial value of the AtomicInteger should be initialized from some activity's saved state rather than starting at 0. If the notification IDs need to be unique across restarts of the app (again, where the app process may be killed off), then the latest value should be saved somewhere (probably to shared prefs) after every increment and restored when the app starts.

Upvotes: 115

Related Questions