Android多行通知如Gmail应用程序

33
我试图创建像 Gmail 应用程序下面的图片所示的多行通知(将 5 条通知分组为一条通知)。 enter image description here 我尝试了各种示例,但似乎只能创建单个通知。
   public void createSingleNotification(String title, String messageText, String tickerttext) {
        int icon = R.drawable.notification_icon; // icon from resources
        CharSequence tickerText = tickerttext; // ticker-text
        long when = System.currentTimeMillis(); // notification time
        Context context = getApplicationContext(); // application Context
        CharSequence contentTitle = title; // expanded message title
        CharSequence contentText = messageText; // expanded message text
        Intent notificationIntent = new Intent(this, MainActivity.class);

        Bundle xtra = new Bundle();
        xtra.putString("title", title);
        xtra.putString("message", messageText);

        notificationIntent.putExtras(xtra);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
          notificationIntent, PendingIntent.FLAG_ONE_SHOT
            + PendingIntent.FLAG_UPDATE_CURRENT);
        String ns = Context.NOTIFICATION_SERVICE;

        NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
        Notification notification = new Notification(icon, tickerText, when);
        notification.setLatestEventInfo(context, contentTitle, contentText,   contentIntent);
        notification.defaults |= Notification.DEFAULT_LIGHTS;
        notification.defaults |= Notification.DEFAULT_SOUND;
        notification.defaults |= Notification.FLAG_AUTO_CANCEL;
        notification.flags = Notification.DEFAULT_LIGHTS
          | Notification.FLAG_AUTO_CANCEL;
        final int HELLO_ID = 0;
        mNotificationManager.notify(HELLO_ID, notification);
      }

我不确定如何创建一个可以添加行的通知组。


可以通过自定义用户界面实现。 - bitsabhi
5个回答

35
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
    .setSmallIcon(R.drawable.notification_icon)
    .setContentTitle("Event tracker")
    .setContentText("Events received")
NotificationCompat.InboxStyle inboxStyle =
        new NotificationCompat.InboxStyle();

String[] events = {"line 1","line 2","line 3","line 4","line 5","line 6"};
// Sets a title for the Inbox in expanded layout
inboxStyle.setBigContentTitle("Event tracker details:");
...
// Moves events into the expanded layout
for (int i=0; i < events.length; i++) {
    inboxStyle.addLine(events[i]);
}
// Moves the expanded layout object into the notification object.
mBuilder.setStyle(inboxStyle);

...
// Issue the notification here.

1
那么事件从哪里来?String数组是空的吗? - JPM
1
很好的例子!谢谢。 - t0m
好例子!谢谢。 - Manthan Patel

28

谢谢,很高兴知道它被称为Big View Notification。我找到的所有教程都是一次创建多行通知。我想要一种创建单行通知的方法,然后在需要时添加更多行。 - user3013243
3
这是Big View的链接。 - Ajoy

10

我已经找到解决方案:确保创建广播接收器来在通知消失时清除数组堆栈

    static ArrayList<String> notifications = new ArrayList<>();

private static void sendNotification(String messageBody,Context cxt) {

    //onDismiss Intent
    Intent intent = new Intent(cxt, MyBroadcastReceiver.class);
    PendingIntent broadcastIntent = PendingIntent.getBroadcast(cxt.getApplicationContext(), 0, intent, 0);

    //OnClick Listener
    startWFApplication().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(cxt, 0, startWFApplication(),
            PendingIntent.FLAG_ONE_SHOT);

    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(cxt)
            .setSmallIcon(R.drawable.fevicon)
            .setContentTitle("Title")
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);
    NotificationCompat.InboxStyle inboxStyle =
            new NotificationCompat.InboxStyle();
    // Sets a title for the Inbox in expanded layout
    inboxStyle.setBigContentTitle("Title - Notification");
    inboxStyle.setSummaryText("You have "+notifications.size()+" Notifications.");
    // Moves events into the expanded layout
    notifications.add(messageBody);
    for (int i=0; i < notifications.size(); i++) {
        inboxStyle.addLine(notifications.get(i));
    }
    // Moves the expanded layout object into the notification object.
    notificationBuilder.setStyle(inboxStyle);

    NotificationManager notificationManager =
            (NotificationManager) cxt.getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0, notificationBuilder.build());
    notificationBuilder.setDeleteIntent(broadcastIntent);
}
public static Intent startWFApplication(){
    Intent launchIntent = new Intent();
    launchIntent.setComponent(new ComponentName("your.package", "Yyour.package.servicename"));
    return launchIntent;
}

BroadCastReceiver的代码应该长这样:

public class MyBroadcastReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {
        Notification.notifications.clear();
     }

  }

在清单文件中添加以下内容:

    <receiver
    android:name="your.package.MyBroadcastReceiver"
    android:exported="false" >
    </receiver>

但我认为当我从最近的应用程序中清除应用程序时,通知列表将会为空。 - Jishant
我应用了上述代码,但在使用 FCM 控制台发送消息时,它不像 Gmail 应用程序那样显示通知。 - Firdosh
它正在工作,谢谢 :-) 但只有在应用程序在前台时才能工作,在后台时无法工作。 - Firdosh
@FirdoshAnsari 我认为你需要确保广播接收器是否正常工作。尝试在每次调用服务时放置一些日志,看看是否生成了日志。 - Sufiyan Ansari

7
我知道这个问题早就被问过了,可能像我一样的很多用户也在搜索,但是我将提供通知的完整代码。想象一下这样的场景:你有一个聊天应用程序,并且希望按每个用户分组获得通知!最好的方法是通过唯一的用户ID进行通知,因此你必须编写单个代码来通知,因为如果你针对低于API级别23的目标用户,那么你无法猜测此时有多少通知存在,而这种情况已经超出了大部分用户的视线。那么当你想要分组每个用户收到的通知并保持逻辑时,你该怎么办呢?我使用了共享首选项和一些轻微的逻辑来实现最佳方式,让我在代码中发布注释。

(通过这种方式,你可以针对较低的API,使KitKat也能处理此逻辑)

这个类模拟了一个测试通知。

/**
 * Simple id just for test
 */
private int NOTIFICATION_ID = 1;
private static int value = 0;
Notification.InboxStyle inboxStyle = new Notification.InboxStyle();
private NotificationCompat.Builder mCopat;
private Bitmap bitmap;
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
    mCopat = new NotificationCompat.Builder(getApplicationContext());

    /**
     * Here we create shared preferences.Probably you will create some helper class to access shared preferences from everywhere
     */
    sharedPreferences = getSharedPreferences("shared", MODE_PRIVATE);
    editor = sharedPreferences.edit();

    /**
     * I clear this for test purpose.
     */
    editor.clear();
    editor.commit();
}


public void hey(View view) {

    /**
     * Add notification,let`s say add 4 notifications with same id which will be grouped as single and after it add the rest which will be grouped as new notification.
     */
    int clickedTime = value++;
    if (clickedTime == 4) {
        NOTIFICATION_ID++;
    }


    /**
     * Here is the important part!We must check whether notification id inserted inside the shared preferences or no.If inserted IT MEANS THAT WE HAVE an notification
     * to where we should add this one (add the new one to the existing group in clear way)
     */
    if (sharedPreferences.getString(String.valueOf(NOTIFICATION_ID), null) != null) {
        Log.d("fsafsafasfa", "hey: " + "not null adding current");

        /**
         * TAKE A NOTICE YOU MUST NOT CREATE A NEW INSTANCE OF INBOXSTYLE, OTHERWISE, IT WON`T WORK. JUST ADD VALUES TO EXISTING ONE
         */

        NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification.Builder builder = new Notification.Builder(this);
        builder.setContentTitle("Lanes");
        builder.setContentText("Notification from Lanes " + value);
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setLargeIcon(bitmap);
        builder.setAutoCancel(true);

        /**
         * By this line you actually add an value to the group,if the notification is collapsed the 'Notification from Lanes' text will be displayed and nothing more
         * otherwise if it is expanded the actual values (let`s say we have 5 items added to notification group) will be displayed.
         */
        inboxStyle.setBigContentTitle("Enter Content Text");
        inboxStyle.addLine("hi events " + value);


        /**
         * This is important too.Send current notification id to the MyBroadcastReceiver which will delete the id from sharedPrefs as soon as the notification is dismissed
         * BY USER ACTION! not manually from code.
         */
        Intent intent = new Intent(this, MyBroadcastReceiver.class);
        intent.putExtra("id", NOTIFICATION_ID);


        PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);

        /**
         * Simply set delete intent.
         */
        builder.setDeleteIntent(pendingIntent);
        builder.setStyle(inboxStyle);
        nManager.notify("App Name", NOTIFICATION_ID, builder.build());

        /**
         * Add id to shared prefs as KEY so we can delete it later
         */
        editor.putString(String.valueOf(NOTIFICATION_ID), "notification");
        editor.commit();
    } else {

        /***
         * Here is same logic EXCEPT that you do create an INBOXSTYLE instance so the values are added to actually separate notification which will just be created now!
         * The rest logic is as same as above!
         */

        /**
         * Ok it gone to else,meaning we do no have any active notifications to add to,so just simply create new separate notification 
         * TAKE A NOTICE to be able to insert new values without old ones you must call new instance of InboxStyle so the old one will not take the place in new separate
         * notification.
         */
        Log.d("fsafsafasfa", "hey: " + " null adding new");
        inboxStyle = new Notification.InboxStyle();
        NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification.Builder builder = new Notification.Builder(this);
        builder.setContentTitle("Lanes");
        builder.setContentText("Notification from Lanes " + value);
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setLargeIcon(bitmap);
        builder.setAutoCancel(true);
        inboxStyle.setBigContentTitle("Enter Content Text");
        inboxStyle.addLine("hi events " + value);

        Intent intent = new Intent(this, MyBroadcastReceiver.class);
        intent.putExtra("id", NOTIFICATION_ID);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
        builder.setDeleteIntent(pendingIntent);

        builder.setStyle(inboxStyle);
        nManager.notify("App Name", NOTIFICATION_ID, builder.build());
        editor.putString(String.valueOf(NOTIFICATION_ID), "notification");
        editor.commit();

    }

}
}

删除意图的广播接收器。不要忘记在清单文件中添加接收器!
public class MyBroadcastReceiver extends BroadcastReceiver {

/**
 * Receive swipe/dismiss or delete action from user.This will not be triggered if you manually cancel the notification.
 * @param context
 * @param intent
 */
@Override
public void onReceive(Context context, Intent intent) {

    /**
     * As soon as received,remove it from shared preferences,meaning the notification no longer available on the tray for user so you do not need to worry.
     */
    SharedPreferences sharedPreferences = context.getSharedPreferences("shared", context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.remove(String.valueOf(intent.getExtras().getInt("id")));
    editor.commit();
}
}

0

目前还没有“通知组”的概念,而是由多行文本组成的单个通知(正如已经指出的那样,这是使用bigContentView完成的,您需要使用Builder来创建)。要更新通知以添加更多数据,只需再次发布它(具有相同的ID和标记),并在BigTextStyle中使用更大的字符串或在InboxStyle中使用更多行。


谢谢,我使用BigTextStyle创建了一个BigView通知。我正在想办法更新通知中显示的消息。我知道可以使用相同的ID更新通知。但是是否有一种方法可以获取当前在通知中显示的消息并将其保存为字符串,以便在更新通知之前根据需要进行编辑? - user3013243
2
不,你必须自己跟踪那些数据。一旦发布了通知对象,你就无法真正地获取它的内容。 - dsandler
谢谢,我会在需要时存储数据并创建带有更新数据的通知。 - user3013243

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接