ฉันจะอัปเดตข้อความแจ้งเตือนสำหรับบริการเบื้องหน้าใน Android ได้อย่างไร


139

ฉันมีการตั้งค่าบริการเบื้องหน้าใน Android ฉันต้องการอัปเดตข้อความแจ้งเตือน ฉันกำลังสร้างบริการดังที่แสดงด้านล่าง

ฉันจะอัปเดตข้อความแจ้งเตือนที่ตั้งค่าไว้ในบริการส่วนหน้านี้ได้อย่างไร แนวทางปฏิบัติที่ดีที่สุดในการอัปเดตการแจ้งเตือนคืออะไร โค้ดตัวอย่างใด ๆ จะได้รับการชื่นชม

public class NotificationService extends Service {

    private static final int ONGOING_NOTIFICATION = 1;

    private Notification notification;

    @Override
    public void onCreate() {
        super.onCreate();

        this.notification = new Notification(R.drawable.statusbar, getText(R.string.app_name), System.currentTimeMillis());
        Intent notificationIntent = new Intent(this, AbList.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        this.notification.setLatestEventInfo(this, getText(R.string.app_name), "Update This Text", pendingIntent);

        startForeground(ONGOING_NOTIFICATION, this.notification);

    }

ฉันกำลังสร้างบริการในกิจกรรมหลักของฉันดังที่แสดงด้านล่าง:

    // Start Notification Service
    Intent serviceIntent = new Intent(this, NotificationService.class);
    startService(serviceIntent);

คำตอบ:


63

ฉันคิดว่าการโทรstartForeground()อีกครั้งด้วย ID ที่ไม่ซ้ำกันและNotificationข้อมูลใหม่จะใช้งานได้แม้ว่าฉันจะไม่ได้ลองใช้สถานการณ์นี้

อัปเดต: ตามความคิดเห็นคุณควรใช้ NotifcationManager เพื่ออัปเดตการแจ้งเตือนและบริการของคุณยังคงอยู่ในโหมดเบื้องหน้า ลองดูคำตอบด้านล่าง


1
คุณช่วยยกตัวอย่างว่าฉันจะเรียกสิ่งนั้นจากกิจกรรมของฉันได้อย่างไร ฉันยังไม่พบตัวอย่างที่ดีเกี่ยวกับวิธีการโทรในบริการเบื้องหน้าของฉัน
ลุค

1
@ ลุค: มีรูปแบบการใช้บริการมากมายและฉันไม่รู้ว่าคุณกำลังติดตามอะไรอยู่ หากคุณกำลังเรียกร้องstartService()ให้ส่งคำสั่งไปยังบริการให้โทรstartService()อีกครั้งเพื่อบอกให้อัปเดตข้อความ หรือหากคุณกำลังโทรbindService()ให้เพิ่มวิธีการใน API ของคุณเพื่อให้บริการอัปเดตข้อความ หรือพิจารณาว่าบริการควรเป็นผู้ตัดสินใจว่าจะอัปเดตข้อความหรือไม่ หรือบางทีข้อความอาจเป็นสิ่งSharedPeferenceที่บริการมีผู้ฟังอยู่ เป็นไปไม่ได้ที่จะให้คำแนะนำที่ถูกต้องในบทคัดย่อ
CommonsWare

9
เพื่อชี้แจงเพิ่มเติม: คุณไม่สามารถชุดประกาศโดยcancel() startForeground()คุณต้องลบสถานะเบื้องหน้าของบริการออกไป (ใช้stopForeground()ถ้าคุณต้องการให้ข้อความสัญลักษณ์ปรากฏขึ้นอีกครั้งฉันเสียเวลาไปหลายชั่วโมงเพราะคำตอบเหล่านี้ทำให้ฉันเชื่อว่ามันเป็นไปได้จริง
slinden77

4
ฉันได้ลดคะแนนคำตอบนี้เนื่องจากเป็นความผิดอย่างชัดเจน: developer.android.com/training/notify-user/managing.htmlโปรด @CommonsWare พิจารณาลบคำตอบนี้เนื่องจากคะแนนชื่อเสียงที่สูงของคุณทำให้คำตอบนี้เป็น "ความจริงอันศักดิ์สิทธิ์" สำหรับ เบราว์เซอร์ทั่วไป ขอบคุณ.
HYS

2
ไม่ได้ผลสำหรับฉัน (แม้ว่าฉันจำได้ว่าใช้วิธีเดียวกันนี้ในโครงการก่อนหน้านี้) ใช้NotificationManagerงานได้ตามที่ฉันคาดไว้
user149408

227

เมื่อคุณต้องการอัปเดตการแจ้งเตือนที่กำหนดโดย startForeground () เพียงแค่สร้างการแจ้งเตือนใหม่จากนั้นใช้ NotificationManager เพื่อแจ้งเตือน

ประเด็นสำคัญคือการใช้รหัสการแจ้งเตือนเดียวกัน

ฉันไม่ได้ทดสอบสถานการณ์ของการเรียก startForeground () ซ้ำ ๆ เพื่ออัปเดตการแจ้งเตือน แต่ฉันคิดว่าการใช้ NotificationManager.notify จะดีกว่า

การอัปเดตการแจ้งเตือนจะไม่ลบบริการออกจากสถานะเบื้องหน้า (สามารถทำได้โดยการเรียกใช้ stopForground เท่านั้น)

ตัวอย่าง:

private static final int NOTIF_ID=1;

@Override
public void onCreate (){
    this.startForeground();
}

private void startForeground() {
    startForeground(NOTIF_ID, getMyActivityNotification(""));
}

private Notification getMyActivityNotification(String text){
    // The PendingIntent to launch our activity if the user selects
    // this notification
    CharSequence title = getText(R.string.title_activity);
    PendingIntent contentIntent = PendingIntent.getActivity(this,
            0, new Intent(this, MyActivity.class), 0);

    return new Notification.Builder(this)
            .setContentTitle(title)
            .setContentText(text)
            .setSmallIcon(R.drawable.ic_launcher_b3)
            .setContentIntent(contentIntent).getNotification();     
}

/**
 * This is the method that can be called to update the Notification
 */
private void updateNotification() {
    String text = "Some text that will update the notification";

    Notification notification = getMyActivityNotification(text);

    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(NOTIF_ID, notification);
}

เอกสารรัฐ

NotificationManager.notify()การตั้งค่าการแจ้งเตือนเพื่อที่จะสามารถได้รับการปรับปรุงปัญหามันมีรหัสการแจ้งเตือนโดยการเรียก หากต้องการอัปเดตการแจ้งเตือนนี้หลังจากที่คุณได้ออกให้อัปเดตหรือสร้าง NotificationCompat.Builderวัตถุสร้างNotificationวัตถุจากนั้นและออกNotificationด้วย ID เดียวกับที่คุณใช้ก่อนหน้านี้ หากยังคงมองเห็นการแจ้งเตือนก่อนหน้านี้ระบบจะอัปเดตจากเนื้อหาของNotificationออบเจ็กต์ หากการแจ้งเตือนก่อนหน้านี้ถูกปิดการแจ้งเตือนใหม่จะถูกสร้างขึ้นแทน


35
นี่คือคำตอบที่ถูกต้อง! คำตอบข้างต้นผิดและทำให้เข้าใจผิดมาก คุณไม่จำเป็นต้องเริ่มบริการของคุณใหม่เพียงเพื่อให้คุณอัปเดตการแจ้งเตือนที่ไร้สาระ
Radu

7
@Radu ในขณะที่ฉันยอมรับว่านี่เป็นคำตอบที่ดีที่สุด (หลีกเลี่ยงเส้นทางรหัสที่ยาวกว่าเล็กน้อยที่ใช้โดยคำตอบของ Commonsware) คุณเข้าใจผิดว่าคำตอบของ Commonsware ทำอะไร - start / stopForegound ไม่เริ่ม / หยุดบริการ แต่ก็ส่งผลต่อความเป็นไปได้ .
Stevie

@Stevie ขอบคุณที่ Stevie คุณน่าจะใช่ ฉันก็จะไม่ยุ่งกับมัน!
Radu

โทรnotify()หรือทั้งนำไปสู่การเรียกร้องstartForeground() onStartCommand()
M. Reza Nasirloo

10
ปัญหาในการใช้NotificationManagerเพื่ออัปเดตการแจ้งเตือนที่แสดงด้วยstartForegroundคือการโทรstopForegroundจะไม่ลบการแจ้งเตือนอีกต่อไป การอัปเดตด้วยการเรียกอื่นเพื่อstartForegroundขัดขวางปัญหานั้น
Tad

23

การปรับปรุงคำตอบ Luca Manzo ใน Android 8.0+ เมื่ออัปเดตการแจ้งเตือนจะส่งเสียงและแสดงเป็น Heads-up
เพื่อป้องกันไม่ให้คุณต้องเพิ่มsetOnlyAlertOnce(true)

ดังนั้นรหัสคือ:

private static final int NOTIF_ID=1;

@Override
public void onCreate(){
        this.startForeground();
}

private void startForeground(){
        startForeground(NOTIF_ID,getMyActivityNotification(""));
}

private Notification getMyActivityNotification(String text){
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
        ((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(
        NotificationChannel("timer_notification","Timer Notification",NotificationManager.IMPORTANCE_HIGH))
}

        // The PendingIntent to launch our activity if the user selects
        // this notification
        PendingIntent contentIntent=PendingIntent.getActivity(this,
        0,new Intent(this,MyActivity.class),0);

        return new NotificationCompat.Builder(this,"my_channel_01")
        .setContentTitle("some title")
        .setContentText(text)
        .setOnlyAlertOnce(true) // so when data is updated don't make sound and alert in android 8.0+
        .setOngoing(true)
        .setSmallIcon(R.drawable.ic_launcher_b3)
        .setContentIntent(contentIntent)
        .build();
}

/**
 * This is the method that can be called to update the Notification
 */
private void updateNotification(){
        String text="Some text that will update the notification";

        Notification notification=getMyActivityNotification(text);

        NotificationManager mNotificationManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(NOTIF_ID,notification);
}

คุณช่วยวันของฉัน ขอบคุณ
Rubén Viguera

2
ไม่มีคีย์เวิร์ดน่าจะnew NotificationChannel
7 ชม

เพื่อให้เราสามารถส่งหมายเลขใดก็ได้ไปยัง notification_id? อื่นที่ไม่ใช่ 0?
Wini

5

นี่คือรหัสที่จะทำเช่นนั้นในการให้บริการของคุณ สร้างการแจ้งเตือนใหม่ แต่ขอให้ผู้จัดการการแจ้งเตือนแจ้งรหัสการแจ้งเตือนเดียวกับที่คุณใช้ใน startForeground

Notification notify = createNotification();
final NotificationManager notificationManager = (NotificationManager) getApplicationContext()
    .getSystemService(getApplicationContext().NOTIFICATION_SERVICE);

notificationManager.notify(ONGOING_NOTIFICATION, notify);

สำหรับโค้ดตัวอย่างทั้งหมดคุณสามารถตรวจสอบได้ที่นี่:

https://github.com/plateaukao/AutoScreenOnOff/blob/master/src/com/danielkao/autoscreenonoff/SensorMonitorService.java


ฉันไม่แน่ใจว่านี่จะคงสถานะเบื้องหน้าของ startService
Martin Marconcini

@Daniel Kao วิธีแก้ปัญหาของคุณไม่ได้เริ่มบริการเบื้องหน้า
IgorGanapolsky

4
แก้ไขฉันถ้าฉันผิด แต่คนอื่นช่วยโหวตคำตอบนี้ได้โปรดอธิบายเพิ่มเติมว่ามีอะไรผิดปกติหรือไม่ คำถามไม่ได้ถามถึงวิธีเริ่มบริการ Foreground แต่จะอัปเดตการแจ้งเตือนของบริการเบื้องหน้าได้อย่างไร นี่เป็นคำตอบเดียวกับ Luca ที่ผู้คนเห็นด้วยกับการทำงานและรักษาสถานะเบื้องหน้า
TheIT

@TheIT มันไม่ทำงาน สถานะการแจ้งเตือนกลายเป็นnot foregroundสำหรับforeground createdข้อความ
Vyacheslav

1
ซึ่งจะส่งผลให้เกิดการแจ้งเตือนซ้ำเนื่องจากstartForeground ()ถูกเรียกไปแล้ว
IgorGanapolsky

2

ดูเหมือนว่าไม่มีคำตอบใดที่มีอยู่แสดงวิธีจัดการกรณีทั้งหมด - เพื่อ startForeground หากเป็นการโทรครั้งแรก แต่อัปเดตการแจ้งเตือนสำหรับการโทรครั้งต่อไป

คุณสามารถใช้รูปแบบต่อไปนี้เพื่อตรวจจับกรณีที่ถูกต้อง:

private void notify(@NonNull String action) {
    boolean isForegroundNotificationVisible = false;
    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    StatusBarNotification[] notifications = notificationManager.getActiveNotifications();
    for (StatusBarNotification notification : notifications) {
        if (notification.getId() == FOREGROUND_NOTE_ID) {
            isForegroundNotificationVisible = true;
            break;
        }
    }
    Log.v(getClass().getSimpleName(), "Is foreground visible: " + isForegroundNotificationVisible);
    if (isForegroundNotificationVisible){
        notificationManager.notify(FOREGROUND_NOTE_ID, buildForegroundNotification(action));
    } else {
        startForeground(FOREGROUND_NOTE_ID, buildForegroundNotification(action));
    }
}

นอกจากนี้คุณต้องสร้างการแจ้งเตือนและช่องเช่นเดียวกับคำตอบอื่น ๆ :

private Notification buildForegroundNotification(@NonNull String action) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        createNotificationChannel();
    }
    //Do any customization you want here
    String title;
    if (ACTION_STOP.equals(action)) {
        title = getString(R.string.fg_notitifcation_title_stopping);
    } else {
        title = getString(R.string.fg_notitifcation_title_starting);
    }
    //then build the notification
    return new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setOngoing(true)
            .build();
}

@RequiresApi(Build.VERSION_CODES.O)
private void createNotificationChannel(){
    NotificationChannel chan = new NotificationChannel(CHANNEL_ID, getString(R.string.fg_notification_channel), NotificationManager.IMPORTANCE_DEFAULT);
    chan.setLightColor(Color.RED);
    chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    assert manager != null;
    manager.createNotificationChannel(chan);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.