Począwszy od Androida w wersji 26 interfejsu API, usługi działające na pierwszym planie wymagają trwałych powiadomień. Ten wymóg ma zapobiegać ukrywaniu usług, które mogą nadmiernie obciążać zasoby systemowe, w tym zwłaszcza baterię. Ten wymóg stwarza potencjalny problem: jeśli aplikacja z wieloma usługami działającymi na pierwszym planie nie będzie starannie zarządzać powiadomieniem, tak aby było ono udostępniane wszystkim usługom, może dojść do sytuacji, w której będzie wyświetlanych wiele trwałych powiadomień, których nie można zamknąć, co spowoduje niepożądany bałagan na aktywnej liście powiadomień.
Problem ten staje się bardziej złożony, gdy używasz pakietów SDK, takich jak Navigation SDK, które uruchamiają usługi działające na pierwszym planie niezależnie od aplikacji i mają własne, niezależne, trwałe powiadomienia, co utrudnia ich konsolidację.
Aby rozwiązać te problemy, w Navigation SDK w wersji 1.11 wprowadziliśmy prosty interfejs API, który pomaga zarządzać trwałymi powiadomieniami w aplikacji, w tym w pakiecie SDK.

Komponenty
Menedżer usług działających na pierwszym planie udostępnia otoczkę dla klasy usług działających na pierwszym planie w Androidzie i klasy trwałych powiadomień. Główną funkcją tej otoczki jest wymuszanie ponownego użycia identyfikatora powiadomienia, tak aby powiadomienie było udostępniane wszystkim usługom działającym na pierwszym planie, które korzystają z menedżera.

Navigation SDK zawiera statyczne metody inicjowania i pobierania singletonu ForegroundServiceManager. Ten singleton można zainicjować tylko raz w całym cyklu życia Navigation SDK. Dlatego jeśli używasz jednego z wywołań inicjujących (initForegroundServiceManagerMessageAndIntent() lub initForegroundServiceManagerProvider()), otocz je blokiem try-catch na wypadek, gdyby ścieżka kodu została ponownie wykonana. Jeśli wywołasz którąkolwiek z tych metod więcej niż raz, Navigation SDK
zgłosi wyjątek czasu wykonania, chyba że
najpierw wyczyścisz wszystkie odwołania do ForegroundServiceManager i przed każdym kolejnym wywołaniem wywołasz
clearForegroundServiceManager().
Cztery parametry initForegroundServiceManagerMessageAndIntent() to application, notificationId, defaultMessage i resumeIntent. Jeśli ostatnie 3 parametry mają wartość null, powiadomienie jest standardowym powiadomieniem Navigation SDK. Nadal można ukryć inne usługi działające na pierwszym planie w aplikacji za tym powiadomieniem. Parametr notificationId określa identyfikator powiadomienia, który ma być używany w powiadomieniu. Jeśli ma wartość null, używana jest dowolna wartość. Możesz ustawić go jawnie, aby uniknąć konfliktów z innymi powiadomieniami, np. z innego pakietu SDK. defaultMessage to ciąg znaków wyświetlany, gdy system nie nawiguje. resumeIntent to intencja, która jest uruchamiana po kliknięciu powiadomienia. Jeśli resumeIntent ma wartość null, kliknięcia powiadomienia są ignorowane.
Trzy parametry initForegroundServiceManagerProvider() to application, notificationId i notificationProvider. Jeśli ostatnie 2 parametry mają wartość null, powiadomienie jest standardowym powiadomieniem Navigation SDK. Parametr notificationId określa identyfikator powiadomienia, który ma być używany w powiadomieniu. Jeśli ma wartość null, używana jest dowolna wartość. Możesz ustawić go jawnie, aby uniknąć konfliktów z innymi powiadomieniami, np. z innego pakietu SDK. Jeśli ustawisz notificationProvider, dostawca zawsze będzie odpowiedzialny za generowanie powiadomienia do wyświetlenia.
Metoda getForegroundServiceManager() w Navigation SDK zwraca singleton menedżera usług działających na pierwszym planie. Jeśli nie został jeszcze wygenerowany, jest to równoznaczne z wywołaniem initForegroundServiceManagerMessageAndIntent() z parametrami notificationId, defaultMessage i resumeIntent o wartości null.
ForegroundServiceManager ma 3 proste metody. Pierwsze 2 służą do przenoszenia usługi na pierwszy plan i poza niego. Zazwyczaj są wywoływane z poziomu utworzonej usługi. Użycie tych metod zapewnia, że usługi są powiązane z udostępnionym trwałym powiadomieniem. Ostatnia metoda, updateNotification(), informuje menedżera, że powiadomienie zostało zmienione i powinno zostać ponownie wyrenderowane.
Jeśli potrzebujesz pełnej kontroli nad udostępnionym trwałym powiadomieniem, interfejs API udostępnia interfejs NotificationContentProvider do definiowania dostawcy powiadomień, który zawiera jedną metodę pobierania powiadomienia z bieżącą treścią. Udostępnia też klasę bazową, której możesz opcjonalnie użyć do zdefiniowania dostawcy. Jednym z głównych celów klasy bazowej jest umożliwienie wywołania updateNotification() bez konieczności uzyskiwania dostępu do ForegroundServiceManager. Jeśli używasz instancji dostawcy powiadomień do odbierania nowych wiadomości powiadomień, możesz bezpośrednio wywołać tę metodę wewnętrzną, aby wyrenderować wiadomość w powiadomieniu.
Scenariusze użycia
W tej sekcji opisujemy scenariusze użycia udostępnionych trwałych powiadomień.
- Ukrywanie trwałych powiadomień innych usług działających na pierwszym planie
- Najprostszy scenariusz to zachowanie dotychczasowego działania i używanie trwałego powiadomienia tylko do renderowania informacji z Navigation SDK. Inne usługi mogą ukrywać się za tym powiadomieniem, używając metod
startForeground()istopForeground()menedżera usług działających na pierwszym planie. - Ukrywanie trwałych powiadomień innych usług działających na pierwszym planie, ale ustawianie domyślnego tekstu wyświetlanego, gdy nie ma nawigacji
- Drugi najprostszy scenariusz to zachowanie dotychczasowego działania i używanie
trwałego powiadomienia tylko do renderowania informacji z Navigation SDK, z wyjątkiem
sytuacji, gdy system nie nawiguje. Gdy system nie nawiguje, zamiast domyślnego ciągu Navigation SDK, który zawiera tekst "Mapy Google", wyświetla się ciąg znaków podany w
initForegroundServiceManagerMessageAndIntent(). Możesz też użyć tego wywołania, aby ustawić intencję wznawiania, która jest uruchamiana po kliknięciu powiadomienia. - Przejęcie pełnej kontroli nad renderowaniem trwałego powiadomienia
- Ostatni scenariusz wymaga zdefiniowania i utworzenia dostawcy powiadomień
oraz przekazania go do
ForegroundServiceManagerza pomocąinitForegroundServiceManagerProvider(). Ta opcja daje Ci pełną kontrolę nad tym, co jest renderowane w powiadomieniu, ale też odłącza informacje o powiadomieniu z Navigation SDK od powiadomienia, co powoduje usunięcie przydatnych wskazówek nawigacyjnych wyświetlanych w powiadomieniu. Google nie udostępnia prostego sposobu na pobranie tych informacji i wstawienie ich do powiadomienia.
Przykład dostawcy powiadomień
Poniższy przykład kodu pokazuje, jak tworzyć i zwracać powiadomienia za pomocą prostego dostawcy treści powiadomień.
public class NotificationContentProviderImpl
extends NotificationContentProviderBase
implements NotificationContentProvider {
private String channelId;
private Context context;
private String message;
/** Constructor */
public NotificationContentProviderImpl(Application application) {
super(application);
message = "-- uninitialized --";
channelId = null;
this.context = application;
}
/**
* Sets message to display in the notification. Calls updateNotification
* to display the message immediately.
*
* @param msg The message to display in the notification.
*/
public void setMessage(String msg) {
message = msg;
updateNotification();
}
/**
* Returns the notification as it should be rendered.
*/
@Override
public Notification getNotification() {
Notification notification;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
Spanned styledText = Html.fromHtml(message, FROM_HTML_MODE_LEGACY);
String channelId = getChannelId(context);
notification =
new Notification.Builder(context, channelId)
.setContentTitle("Notifications Demo")
.setStyle(new Notification.BigTextStyle()
.bigText(styledText))
.setSmallIcon(R.drawable.ic_navigation_white_24dp)
.setTicker("ticker text")
.build();
} else {
notification = new Notification.Builder(context)
.setContentTitle("Notification Demo")
.setContentText("testing non-O text")
.build();
}
return notification;
}
// Helper to set up a channel ID.
private String getChannelId(Context context) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
if (channelId == null) {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(
"default", "navigation", NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("For navigation persistent notification.");
notificationManager.createNotificationChannel(channel);
channelId = channel.getId();
}
return channelId;
} else {
return "";
}
}
}
Po utworzeniu NotificationContentProviderImpl połącz z nim Navigation SDK za pomocą tego kodu:
ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);
Ograniczenia i plany na przyszłość
- Pamiętaj, aby wcześnie wywołać
initForegroundServiceManagerMessageAndIntent()lubinitForegroundServiceManagerProvider(), aby oczekiwany scenariusz użycia był dobrze zdefiniowany. Musisz wywołać tę metodę przed utworzeniem nowego nawigatora. - Pamiętaj, aby przechwytywać wyjątki z wywołań
initForegroundServiceManagerMessageAndIntent()lubinitForegroundServiceManagerProvider()na wypadek, gdyby ścieżka kodu została wykonana więcej niż raz. W Navigation SDK w wersji 2.0 wielokrotne wywołanie tej metody zgłasza wyjątek sprawdzany, a nie wyjątek czasu wykonania. - Google może nadal pracować nad zapewnieniem spójnego stylu przez cały czas wyświetlania powiadomienia, który będzie pasował do stylu nagłówka.
- Gdy zdefiniujesz dostawcę powiadomień, możesz kontrolować zachowanie powiadomień wyskakujących za pomocą priorytetu.
- Google nie udostępnia prostego sposobu na pobieranie informacji o szczegółowej nawigacji, które dostawca powiadomień może wstawić do powiadomienia.