Androidのフォアグラウンドサービスの通知テキストを更新するにはどうすればよいですか?


133

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);

回答:


61

私はこのシナリオを試していませんstartForeground()が、同じ一意のIDとNotification新しい情報を使って再度呼び出すとうまくいくと思います。

更新:コメントに基づいて、NotifcationManagerを使用して通知を更新する必要があります。サービスは引き続きフォアグラウンドモードのままです。以下の答えを見てください。


1
私の活動からそれをどのように呼ぶかの例を教えていただけませんか?フォアグラウンドサービスでメソッドを呼び出す方法に関する適切なサンプルを見つけることができませんでした。
ルーク

1
@ルーク:サービスの使用にはいくつものパターンがあり、あなたが何をフォローしているかはわかりません。startService()サービスにコマンドを渡すために呼び出す場合は、startService()もう一度呼び出して、テキストを更新するように指示します。または、を呼び出す場合はbindService()、APIにメソッドを追加して、サービスにテキストを更新させます。または、サービス自体がテキストを更新するかどうかを決定するサービスであるかどうかを検討します。または、おそらくテキストはSharedPeferenceサービスがリスナーを持っているものです。要約で正確なアドバイスをすることは不可能です。
CommonsWare、2011

9
さらに明確にするために:でcancel()通知を設定することはできませんstartForeground()。あなたは、サービス自体(使用のフォアグラウンド状態を削除する必要がありstopForeground()ますが、ティッカーテキストが再び表示されるようにしたい場合は、これらの答えは、それが実際に可能であったと信じて私を導いたので、私は時間を失った。。
slinden77

4
この回答は明らかに間違っているため、反対票を投じました:developer.android.com/training/notify-user/managing.html @CommonsWareは、この回答を削除することを検討してください。カジュアルなブラウザ。ありがとう。
HYS 2016年

2
私にはうまくいきませんでした(以前のプロジェクトでこれと同じ方法を使用したことを覚えていますが)。使用NotificationManagerは期待通りに機能しました。
user149408

224

startForeground()で設定された通知を更新する場合は、新しい通知を作成し、NotificationManagerを使用して通知するだけです。

重要な点は、同じ通知IDを使用することです。

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);
}

ドキュメントの状態

更新できるように通知を設定するには、を呼び出して通知IDを発行しNotificationManager.notify()ます。この通知を発行した後に更新するには、NotificationCompat.Builderオブジェクトを更新または作成し、それからオブジェクトを作成し、 以前に使用したものと同じIDでをNotification発行しNotificationます。以前の通知がまだ表示されている場合、システムはNotificationオブジェクトの内容からそれを更新します。以前の通知が却下された場合は、代わりに新しい通知が作成されます。


35
これが正解です。上記の答えは非常に間違っており、誤解を招くものです。ばかげた通知を更新するためだけにサービスを再起動する必要はありません。
ラドゥ2013年

7
@Radu私はこれが最適な回答であることに同意しますが(Commonswareの回答が取る少し長いコードパスを回避します)、Commonswareの回答が何をしているのかを誤解しています-start / stopForegoundはサービスを開始/停止せず、単にフォアグラウンドに影響します。
スティービー14

@スティービースティービー、ありがとうございます。それでも私はそれを台無しにしないでしょう!
Radu 14

notify()またはのstartForeground()両方を呼び出すと、が呼び出されますonStartCommand()
M. Reza Nasirloo、2015

10
NotificationManager表示される通知の更新にを使用する場合の問題startForegroundは、呼び出しstopForegroundによって通知が削除されなくなることです。別の呼び出しで更新するとstartForeground、その問題を回避できます。
タッド

21

通知を更新するときにAndroid 8.0以降でLuca Manzoの回答を改善すると、通知が鳴り、ヘッドアップとして表示されます。
追加する必要があることを防ぐために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);
}

あなたは私の日を救った。ありがとう
ルベン・Viguera

1
キーワードがありません、そこにあるべきnew NotificationChannel
7hny

5

これがサービスで実行するコードです。新しい通知を作成しますが、startForegroundで使用したものと同じ通知IDを通知するよう通知マネージャーに依頼します。

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 2013年

@Daniel Kaoソリューションがフォアグラウンドサービスを開始しない
IgorGanapolsky 2013

4
私が間違っている場合は訂正してください。この回答に反対票を投じた人々は、何が悪いのかについてもっと説明してください。質問は、フォアグラウンドサービスを開始する方法ではなく、フォアグラウンドサービスの通知を更新する方法を問うものです。これは事実上、人々が機能し、フォアグラウンドの状態を維持することに同意するルカと同じ答えです。
TheIT

@TheIT動作しません。通知のステータスがなるnot foregroundためforeground createdのメッセージ。
Vyacheslav

1
startForeground()がすでに呼び出されているため、これにより通知が重複します。
IgorGanapolsky 2017

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.