Ab Android API-Level 26 sind für Dienste im Vordergrund dauerhafte Benachrichtigungen erforderlich. Diese Anforderung soll verhindern, dass du Dienste ausblendest, die die Systemressourcen, insbesondere den Akku, übermäßig beanspruchen könnten. Diese Anforderung kann zu einem Problem führen: Wenn eine App mit mehreren Diensten im Vordergrund die Benachrichtigung nicht sorgfältig verwaltet, sodass sie von allen Diensten gemeinsam genutzt wird, kann es mehrere dauerhafte, nicht schließbare Benachrichtigungen geben. Das führt zu unerwünschtem Durcheinander in der aktiven Liste der Benachrichtigungen.
Dieses Problem wird noch komplexer, wenn Sie SDKs wie das Navigation SDK verwenden, die Dienste im Vordergrund unabhängig von der App ausführen und eigene, unabhängige dauerhafte Benachrichtigungen haben, was die Zusammenführung erschwert.
Um diese Probleme zu beheben, wurde in Version 1.11 des Navigation SDK eine einfache API eingeführt, mit der sich dauerhafte Benachrichtigungen in der gesamten App, einschließlich des SDK, verwalten lassen.

Komponenten
Der Dienstmanager im Vordergrund bietet einen Wrapper für die Android-Dienstklasse im Vordergrund und die Klasse für persistente Benachrichtigungen. Die Hauptfunktion dieses Wrappers besteht darin, die Wiederverwendung der Benachrichtigungs-ID zu erzwingen, damit die Benachrichtigung von allen Diensten im Vordergrund, die den Manager verwenden, gemeinsam genutzt wird.

Das Navigation SDK enthält statische Methoden zum Initialisieren und Abrufen des ForegroundServiceManager-Singletons. Dieses Singleton kann nur einmal während der Lebensdauer des Navigation SDK initialisiert werden. Wenn Sie einen der Initialisierungsaufrufe (initForegroundServiceManagerMessageAndIntent() oder initForegroundServiceManagerProvider()) verwenden, sollten Sie ihn daher mit einem Try-Catch-Block umschließen, falls dieser Pfad noch einmal aufgerufen wird. Das Navigation SDK löst eine Laufzeitausnahme aus, wenn Sie eine der beiden Methoden mehrmals aufrufen, es sei denn, Sie löschen zuerst alle Verweise auf ForegroundServiceManager und rufen vor jedem nachfolgenden Aufruf clearForegroundServiceManager() auf.
Die vier Parameter von initForegroundServiceManagerMessageAndIntent() sind application, notificationId, defaultMessage und resumeIntent. Wenn die letzten drei Parameter null sind, ist die Benachrichtigung die Standardbenachrichtigung des Navigations-SDK. Es ist weiterhin möglich, andere Dienste im Vordergrund in der App hinter dieser Benachrichtigung auszublenden. Der Parameter notificationId gibt die Benachrichtigungs-ID an, die für die Benachrichtigung verwendet werden soll. Wenn der Wert null ist, wird ein beliebiger Wert verwendet. Sie können sie explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu vermeiden, z. B. von einem anderen SDK. defaultMessage ist ein String, der angezeigt wird, wenn das System nicht navigiert. resumeIntent ist ein Intent, der ausgelöst wird, wenn auf die Benachrichtigung geklickt wird. Wenn resumeIntent null ist, werden Klicks auf die Benachrichtigung ignoriert.
Die drei Parameter von initForegroundServiceManagerProvider() sind application, notificationId und notificationProvider. Wenn die letzten beiden Parameter null sind, ist die Benachrichtigung die Standardbenachrichtigung des Navigations-SDK. Der Parameter notificationId gibt die Benachrichtigungs-ID an, die für die Benachrichtigung verwendet werden soll. Wenn der Wert null ist, wird ein beliebiger Wert verwendet. Sie können sie explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu vermeiden, z. B. von einem anderen SDK. Wenn notificationProvider festgelegt ist, ist der Anbieter immer für die Generierung der zu rendernden Benachrichtigung verantwortlich.
Die Navigation SDK-Methode getForegroundServiceManager() gibt das Singleton des Dienstmanagers im Vordergrund zurück. Wenn Sie noch keinen generiert haben, entspricht dies dem Aufruf von initForegroundServiceManagerMessageAndIntent() mit Nullparametern für notificationId, defaultMessage und resumeIntent.
ForegroundServiceManager bietet drei einfache Methoden. Die ersten beiden dienen dazu, einen Dienst in den Vordergrund und aus dem Vordergrund zu verschieben. Sie werden normalerweise innerhalb des erstellten Dienstes aufgerufen. Mit diesen Methoden wird sichergestellt, dass die Dienste mit der freigegebenen dauerhaften Benachrichtigung verknüpft sind. Die letzte Methode, updateNotification(), signalisiert dem Manager, dass sich die Benachrichtigung geändert hat und neu gerendert werden sollte.
Wenn Sie die vollständige Kontrolle über die freigegebene dauerhafte Benachrichtigung benötigen, bietet die API eine NotificationContentProvider-Schnittstelle zum Definieren eines Benachrichtigungsanbieters, der eine einzelne Methode zum Abrufen einer Benachrichtigung mit dem aktuellen Inhalt enthält. Außerdem wird eine Basisklasse bereitgestellt, mit der Sie den Anbieter optional definieren können. Einer der Hauptzwecke der Basisklasse besteht darin, dass sie eine Möglichkeit bietet, updateNotification() aufzurufen, ohne auf die ForegroundServiceManager zugreifen zu müssen. Wenn Sie eine Instanz des Benachrichtigungsanbieters verwenden, um neue Benachrichtigungen zu erhalten, können Sie diese interne Methode direkt aufrufen, um die Nachricht in der Benachrichtigung zu rendern.
Anwendungsszenarien
In diesem Abschnitt werden die Nutzungsszenarien für die Verwendung von freigegebenen nichtflüchtigen Benachrichtigungen beschrieben.
- Dauerhafte Benachrichtigungen von anderen Diensten im Vordergrund ausblenden
- Am einfachsten ist es, das aktuelle Verhalten beizubehalten und die dauerhafte Benachrichtigung nur zum Rendern von Informationen des Navigations-SDK zu verwenden. Andere Dienste können sich hinter dieser Benachrichtigung verbergen, indem sie die Methoden
startForeground()undstopForeground()des Managers für Dienste im Vordergrund verwenden. - Dauerhafte Benachrichtigungen anderer Dienste im Vordergrund ausblenden, aber Standardtext festlegen, der angezeigt wird, wenn keine Navigation stattfindet
- Das zweitbeste Szenario ist, das aktuelle Verhalten beizubehalten und die dauerhafte Benachrichtigung nur zum Rendern von Informationen des Navigations-SDK zu verwenden, außer wenn das System nicht navigiert. Wenn das System nicht navigiert, wird der String angezeigt, der für
initForegroundServiceManagerMessageAndIntent()angegeben wurde, und nicht der Standardstring des Navigation SDK, in dem „Google Maps“ erwähnt wird. Du kannst diesen Aufruf auch verwenden, um den Resume-Intent festzulegen, der ausgelöst wird, wenn auf die Benachrichtigung geklickt wird. - Vollständige Kontrolle über das Rendern der dauerhaften Benachrichtigung
- Im letzten Szenario muss ein Benachrichtigungsanbieter definiert und erstellt und mit
initForegroundServiceManagerProvider()an denForegroundServiceManagerübergeben werden. Mit dieser Option haben Sie die volle Kontrolle darüber, was in der Benachrichtigung gerendert wird. Allerdings werden die Benachrichtigungsinformationen des Navigation SDK von der Benachrichtigung getrennt, sodass die hilfreichen detaillierten Routenführungen in der Benachrichtigung nicht mehr angezeigt werden. Google bietet keine einfache Möglichkeit, diese Informationen abzurufen und in die Benachrichtigung einzufügen.
Beispiel für einen Benachrichtigungsanbieter
Im folgenden Codebeispiel wird gezeigt, wie Sie Benachrichtigungen mit einem einfachen Contentanbieter für Benachrichtigungen erstellen und zurückgeben.
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 "";
}
}
}
Nachdem Sie NotificationContentProviderImpl erstellt haben, verbinden Sie das Navigation SDK mit dem folgenden Code:
ForegroundServiceManager f = NavigationApi.getForegroundServiceManager(getApplication());
mNotification = new NotificationContentProviderImpl(getApplication());
NavigationApi.clearForegroundServiceManager();
NavigationApi.initForegroundServiceManagerProvider(getApplication(), null, mNotification);
Einschränkungen und Zukunftspläne
- Rufen Sie
initForegroundServiceManagerMessageAndIntent()oderinitForegroundServiceManagerProvider()frühzeitig auf, damit das erwartete Nutzungsszenario klar definiert ist. Sie müssen diese Methode aufrufen, bevor Sie einen neuen Navigator erstellen. - Achte darauf, Ausnahmen von Aufrufen von
initForegroundServiceManagerMessageAndIntent()oderinitForegroundServiceManagerProvider()abzufangen, falls der Codepfad mehrmals aufgerufen wird. Im Navigation SDK v2.0 wird durch mehrmaliges Aufrufen dieser Methode eine geprüfte Ausnahme anstelle einer Laufzeitausnahme ausgelöst. - Google muss möglicherweise noch daran arbeiten, dass die Benachrichtigung während ihrer gesamten Lebensdauer ein einheitliches Design hat, das dem Design des Headers entspricht.
- Wenn du einen Benachrichtigungsanbieter definierst, kannst du das Verhalten von Heads-up-Benachrichtigungen über die Priorität steuern.
- Google bietet keine einfache Möglichkeit, detaillierte Routenführungsinformationen abzurufen, die ein Benachrichtigungsanbieter in die Benachrichtigung einfügen könnte.