14

Mam usługę Media, która używa funkcji startForeground(), aby wyświetlać powiadomienia po rozpoczęciu odtwarzania. Posiada przyciski pauzy/zatrzymania podczas odtwarzania, przyciski odtwarzania/zatrzymania podczas pauzy.Zezwalaj na anulowanie powiadomienia po wywołaniu stopForeground (fałsz)

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); 
// setup... 

Notification n = mBuilder.build(); 

if (state == State.Playing) { 
    startForeground(mId, n); 
} 
else { 
    stopForeground(false); 
    mNotificationManager.notify(mId, n);   
} 

Tutaj problemem jest to, kiedy pokazać/aktualizacji powiadomień w to przerwał stan, powinno być zabronione, aby ją usunąć. mBuilder.setOngoing(false) wydaje się nie mieć żadnego wpływu, ponieważ poprzedni startForeground przesłania go.

Wywołanie stopForeground(true); z tym samym kodem działa zgodnie z oczekiwaniami, ale powiadomienie miga, ponieważ zostało zniszczone i ponownie utworzone. Czy istnieje sposób na "zaktualizowanie" powiadomienia utworzonego przez startForeground w celu umożliwienia usunięcia go po wywołaniu stop?

Edycja: Tutaj jest pełny kod tworzenia powiadomienia. createNotification jest wywoływany, gdy usługa jest odtwarzana lub wstrzymana.

private void createNotification() { 
    NotificationCompat.Builder mBuilder = 
      new NotificationCompat.Builder(this) 
    .setSmallIcon(R.drawable.ic_launcher) 
    .setContentTitle("No Agenda") 
    .setContentText("Live stream"); 

    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) 
    { 
     if (state == State.Playing) { 
      Intent pauseIntent = new Intent(this, MusicService.class); 
      pauseIntent.setAction(ACTION_PAUSE); 
      PendingIntent pausePendingIntent =  PendingIntent.getService(MusicService.this, 0, pauseIntent, 0);    

      mBuilder.addAction(R.drawable.pause, "Pause", pausePendingIntent); 
      //mBuilder.setOngoing(true); 
     } 
     else if (state == State.Paused) { 
      Intent pauseIntent = new Intent(this, MusicService.class); 
      pauseIntent.setAction(ACTION_PAUSE); 
      PendingIntent pausePendingIntent = PendingIntent.getService(MusicService.this, 0, pauseIntent, 0); 

      mBuilder.addAction(R.drawable.play, "Play", pausePendingIntent); 
      mBuilder.setOngoing(false); 
     } 

     Intent stopIntent = new Intent(this, MusicService.class); 
     stopIntent.setAction(ACTION_STOP); 
     PendingIntent stopPendingIntent = PendingIntent.getService(MusicService.this, 0, stopIntent, 0); 

     setNotificationPendingIntent(mBuilder); 
     mBuilder.addAction(R.drawable.stop, "Stop", stopPendingIntent); 
    } 
    else 
    { 
     Intent resultIntent = new Intent(this, MainActivity.class); 
     PendingIntent intent = PendingIntent.getActivity(this, 0, resultIntent, 0); 

     mBuilder.setContentIntent(intent); 
    } 

    Notification n = mBuilder.build(); 

    if (state == State.Playing) { 
     startForeground(mId, n); 
    } 
    else { 
     stopForeground(true); 
     mNotificationManager.notify(mId, n); 
    } 
} 

@TargetApi(Build.VERSION_CODES.JELLY_BEAN) 
private void setNotificationPendingIntent(NotificationCompat.Builder mBuilder) { 
    Intent resultIntent = new Intent(this, MainActivity.class); 

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); 
    stackBuilder.addParentStack(MainActivity.class); 
    stackBuilder.addNextIntent(resultIntent); 

    PendingIntent resultPendingIntent = 
      stackBuilder.getPendingIntent(
       0, 
       PendingIntent.FLAG_UPDATE_CURRENT 
      ); 

    mBuilder.setContentIntent(resultPendingIntent); 
} 

Follow-up Edit:

Jeden z komentarzy poniżej wspomniano, że odpowiedź może być „kruche”, a od wydaniem Androida 4.3, zachowanie za startForeground uległ zmianie. startForeground zmusi twoją aplikację, by pokazała powiadomienie na pierwszym planie, a metoda powinna zostać wywołana z powiadomieniem do pokazania. Nie testowałem, ale zaakceptowana odpowiedź może już nie działać zgodnie z przeznaczeniem.

Jeśli chodzi o zatrzymywanie migania podczas wywoływania stopForeground, nie sądzę, że warto walczyć z tymi ramami.

Jest kilka additional information on the Android 4.3 notification change here.

+0

Czy możesz pokazać swój kod, gdy próbujesz wywołać 'setOngoing (false)'? Podejrzewam, że powiadomienie nie jest przebudowywane, aby wykryć zmiany, ale trudno to stwierdzić z tego fragmentu. – dsandler

+0

@dsandler Dodałem pełny kod dla createNotification(). –

+0

Chciałbym również podkreślić, że obecnie testuję tylko Jellybean, obecnie 4.2.2 (emulator i telefon), gdzie ustawiam setOngoing (false). Również setOngoing (false) działa, gdy powiadomienie nie jest uruchamiane przez startForeground (i setOngoing (true) jest odkomentowane). –

Odpowiedz

4

Możesz rozważyć zastosowanie innego podejścia.
Od ciebie powinien korzystać z usługi pierwszego planu dla takiego zadania (odtwarzanie multimediów) Sugeruję, abyś nadal robił start foreground(), ale zamiast przekazywać powiadomienia do niego po prostu ustaw id 0 i null powiadomienia tak startForeground(0, null);.

W ten sposób usługa pierwszego planu nie wyświetli żadnego powiadomienia.

Teraz, dla swoich celów, możesz korzystać z regularnych powiadomień i aktualizować ich stany (bieżące, układ, tekst itp.), Dzięki czemu nie jesteś zależny od zachowania w powiadomieniu usługi pierwszoplanowej.

Mam nadzieję, że to pomoże.

+0

To brzmi jak poprawna ścieżka, jednak przekazanie powiadomienia o wartości NULL powoduje zgłoszenie wyjątku IllegalArgumentException na startForeground(). Poniższe pytanie wydaje się wskazywać to samo: http://stackoverflow.com/questions/10962418/startforeground-without-showing-notification –

+0

To interesujące, ponieważ użyłem tej metody kilka razy, i po prostu przetestowałem ją za pomocą pusty projekt. Upewniłem się również, że usługa rzeczywiście działa na pierwszym planie, wysyłając zapytanie do 'PackageManager'. Możesz także spróbować przekazać 0 jako identyfikator w 'startForeground (identyfikator, powiadomienie)' –

+0

Używanie 0 jako działającego id i wszystko działa zgodnie z oczekiwaniami. Każdy identyfikator inny niż 0 wydaje się powodować wyjątek IllegalArgumentException. Idealny! –

2

Według docs To zachowanie jest zgodne z projektem przed Lollipop

Wnioski skierowane do tej lub nowszej wersji dostanie te nowe zmiany w zachowaniu:

...

  • Calling .stopForeground z removeNotification false zmodyfikuje nadal wysłane powiadomienie, dzięki czemu nie jest już zmuszany do kontynuacji.
1

Zamiast stopService(true), nazywając stopService(false) zachowa zgłoszenie to (bez ciągłego stanu), chyba że jest ona oddalona przez użytkownika/usunięty programowo lub jeśli usługa zatrzyma. Dlatego po prostu wywołaj stopService (false) i zaktualizuj powiadomienie, aby pokazać stan wstrzymania, a teraz powiadomienie może zostać odrzucone przez użytkownika. Zapobiega to również flashowaniu, ponieważ nie odtwarzamy powiadomień.

+0

To działa idealnie – Hackmodford