Ab Android API-Level 26 sind für Vordergrunddienste dauerhafte Benachrichtigungen erforderlich. Mit dieser Anforderung soll verhindert werden, dass Sie Dienste ausblenden, die möglicherweise übermäßige Anforderungen an die Systemressourcen stellen, insbesondere an den Akku. Diese Anforderung birgt ein potenzielles Problem: Wenn eine App mit mehreren Vordergrunddiensten die Benachrichtigung nicht sorgfältig verwaltet, sodass sie für alle Dienste freigegeben wird, kann es zu mehreren dauerhaften, nicht schließbaren Benachrichtigungen kommen, was zu unerwünschten Benachrichtigungen in der aktiven Liste der Benachrichtigungen führt.
Dieses Problem wird noch schwieriger, wenn Sie SDKs wie das Navigation SDK verwenden, die Vordergrunddienste unabhängig von der App ausführen und eigene unabhängige dauerhafte Benachrichtigungen haben, die sich nur schwer zusammenführen lassen.
Um diese Probleme zu beheben, wurde im Navigation SDK v1.11 eine einfache API eingeführt, mit der sich dauerhafte Benachrichtigungen in der gesamten App verwalten lassen, einschließlich im SDK.

Komponenten
Der Vordergrunddienst-Manager bietet einen Wrapper für die Android-Vordergrunddienstklasse und die Klasse für dauerhafte Benachrichtigungen. Die Hauptfunktion dieses Wrappers besteht darin, die Wiederverwendung der Benachrichtigungs-ID zu erzwingen, damit die Benachrichtigung für alle Vordergrunddienste freigegeben wird, die den Manager verwenden.

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 in einen Try-Catch-Block einschließen, falls dieser Pfad noch einmal aufgerufen wird. Das Navigation SDK
löst eine Laufzeitausnahme aus, wenn Sie eine der beiden Methoden mehr als einmal aufrufen, es sei denn, Sie
löschen zuerst alle Verweise auf den ForegroundServiceManager und rufen
clearForegroundServiceManager() vor jedem nachfolgenden Aufruf 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 Navigation SDK. Es ist weiterhin möglich, andere Vordergrunddienste in der App hinter dieser Benachrichtigung zu verbergen. Der Parameter notificationId gibt die Benachrichtigungs-ID an, die für die Benachrichtigung verwendet werden soll. Wenn er null ist, wird ein beliebiger Wert verwendet. Sie können ihn explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu vermeiden, z. B. mit Benachrichtigungen 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 Navigation SDK. Der Parameter notificationId gibt die Benachrichtigungs-ID an, die für die Benachrichtigung verwendet werden soll. Wenn er null ist, wird ein beliebiger Wert verwendet. Sie können ihn explizit festlegen, um Konflikte mit anderen Benachrichtigungen zu vermeiden, z. B. mit Benachrichtigungen von einem anderen SDK. Wenn notificationProvider festgelegt ist, ist der Anbieter immer für das Generieren der zu rendernden Benachrichtigung verantwortlich.
Die Methode getForegroundServiceManager() des Navigation SDK gibt das Singleton des Vordergrunddienst-Managers zurück. Wenn Sie noch keines generiert haben, entspricht dies dem Aufruf von initForegroundServiceManagerMessageAndIntent() mit Nullparametern für notificationId, defaultMessage und resumeIntent.
Der ForegroundServiceManager hat drei einfache Methoden. Die ersten beiden dienen dazu, einen Dienst in den Vordergrund zu verschieben und ihn wieder in den Hintergrund zu verschieben. Sie werden in der Regel innerhalb des erstellten Dienstes aufgerufen. Durch die Verwendung dieser Methoden wird sichergestellt, dass die Dienste der freigegebenen dauerhaften Benachrichtigung zugeordnet sind. Die letzte Methode, updateNotification(), kennzeichnet den Manager, dass sich die Benachrichtigung geändert hat und neu gerendert werden muss.
Wenn Sie die vollständige Kontrolle über die freigegebene dauerhafte Benachrichtigung benötigen, bietet die API eine NotificationContentProvider-Schnittstelle zum Definieren eines Benachrichtigungsanbieters, die eine einzelne Methode zum Abrufen einer Benachrichtigung mit dem aktuellen Inhalt enthält. Außerdem wird eine Basisklasse bereitgestellt, die Sie optional verwenden können, um den Anbieter zu definieren. Einer der Hauptzwecke der Basisklasse besteht darin, eine Möglichkeit zu bieten, updateNotification() aufzurufen, ohne auf den 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.
Nutzungsszenarien
In diesem Abschnitt werden die Nutzungsszenarien für die Verwendung freigegebener dauerhafter Benachrichtigungen beschrieben.
- Dauerhafte Benachrichtigungen anderer Vordergrunddienste der App ausblenden
- Das einfachste Szenario besteht darin, das aktuelle Verhalten beizubehalten und die dauerhafte Benachrichtigung nur zum Rendern von Informationen des Navigation SDK zu verwenden. Andere Dienste können hinter dieser Benachrichtigung ausgeblendet werden, indem die Methoden
startForeground()undstopForeground()des Vordergrunddienst-Managers verwendet werden. - Dauerhafte Benachrichtigungen anderer Vordergrunddienste der App ausblenden, aber Standardtext festlegen, der angezeigt wird, wenn nicht navigiert wird
- Das zweit einfachste Szenario besteht darin, das aktuelle Verhalten beizubehalten und die dauerhafte Benachrichtigung nur zum Rendern von Informationen des Navigation SDK zu verwenden, außer wenn das System nicht navigiert. Wenn das System nicht navigiert, wird der
String angezeigt, der an
initForegroundServiceManagerMessageAndIntent()übergeben wurde, und nicht der Standardstring des Navigation SDK, in dem "Google Maps" erwähnt wird. Mit diesem Aufruf können Sie auch den Intent für die Wiederaufnahme festlegen, der ausgelöst wird, wenn auf die Benachrichtigung geklickt wird. - Vollständige Kontrolle über das Rendern der dauerhaften Benachrichtigung
- Im letzten Szenario müssen Sie einen Benachrichtigungsanbieter definieren und erstellen
und ihn mit
initForegroundServiceManagerProvider()an denForegroundServiceManagerübergeben. Mit dieser Option haben Sie die vollständige Kontrolle darüber, was in der Benachrichtigung gerendert wird. Außerdem werden die Benachrichtigungsinformationen des Navigation SDK von der Benachrichtigung getrennt, wodurch die hilfreichen Schritt-für-Schritt-Anweisungen entfernt werden, die in der Benachrichtigung angezeigt werden. Google bietet keine einfache Möglichkeit, diese Informationen abzurufen und in die Benachrichtigung einzufügen.
Beispiel für einen Benachrichtigungsanbieter
Das folgende Codebeispiel zeigt, wie Sie mit einem einfachen Benachrichtigungsinhaltsanbieter 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);
Hinweise 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. - Fangen Sie Ausnahmen von Aufrufen von
initForegroundServiceManagerMessageAndIntent()oderinitForegroundServiceManagerProvider()ab, falls der Codepfad mehr als einmal aufgerufen wird. Im Navigation SDK v2.0 löst der mehrfache Aufruf dieser Methode eine geprüfte Ausnahme und keine Laufzeitausnahme aus. - Google muss möglicherweise noch daran arbeiten, ein einheitliches Styling über die gesamte Lebensdauer der Benachrichtigung hinweg zu erzielen, das mit dem Styling der Kopfzeile übereinstimmt.
- Wenn Sie einen Benachrichtigungsanbieter definieren, können Sie das Verhalten von Pop-up-Benachrichtigungen mit der Priorität steuern.
- Google bietet keine einfache Möglichkeit, Schritt-für-Schritt Informationen abzurufen, die ein Benachrichtigungsanbieter in die Benachrichtigung einfügen könnte.