it-swarm.com.de

Android O - Alter Start-Vordergrunddienst funktioniert noch?

Mit Android O müssen Sie also Ihren Dienst als Vordergrunddienst ausführen, wenn Sie mehr als nur wenige Standortaktualisierungen pro Stunde erhalten möchten.

Mir ist aufgefallen, dass die alte Methode zum Starten eines Vordergrunddienstes auf O ..__ zu funktionieren scheint. 

startForeground(NOTIFICATION_ID, getNotification());

Gemäß dem Verhaltensänderungen-Handbuch hier: https://developer.Android.com/preview/behavior-changes.html

Die NotificationManager.startServiceInForeground () - Methode startet einen Vordergrunddienst. Die alte Art, einen Vordergrunddienst zu starten, funktioniert nicht mehr.

Obwohl die neue Methode nur für O-Targeting funktioniert, scheint die alte Methode immer noch auf einem O-Gerät zu funktionieren, egal ob O-Targeting oder nicht.

Edit Einschließlich Beispiel:

Das Google-Beispielprojekt LocationUpdatesForegroundService enthält ein Arbeitsbeispiel, in dem Sie das Problem aus erster Hand sehen können . https://github.com/googlesamples/Android-play-location/tree/master/LocationUpdatesForegroundService

Die startForeground-Methode scheint ohne Probleme zu funktionieren, ob das Targeting und Compilieren gegen API Level 25 OR, das Targeting und das Compilieren gegen O (wie hier angegeben: https://developer.Android.com/preview/migration.html) #uya )

Also zu reproduzieren:

  1. Konfigurieren Sie die App-Einstellungen wie im vorherigen Link beschrieben
  2. App öffnen
  3. Standortaktualisierungen anfordern
  4. App schließen (entweder über den Zurück-Button oder den Home-Button)

Der Dienst wird im Vordergrund ausgeführt (durch ein Symbol im Benachrichtigungsschatten angezeigt). Standortaktualisierungen werden wie erwartet (alle 10 Sekunden) auch auf einem Gerät ausgeführt, auf dem O ausgeführt wird. Was fehlt mir hier?

27
the_new_mr

Das hat bei mir funktioniert.

  1. Starten Sie in der Aktivitätsklasse den Dienst mithilfe von startForegroundService () anstelle von startService ()
    Intent myService = new Intent(this, MyService.class);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(myService);
    } else {
        startService(myService);
    }
  1. Jetzt in der Service-Klasse in onStartCommand () wie folgt vorgehen
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    ......
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

        Notification.Builder builder = new Notification.Builder(this, Android_CHANNEL_ID)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(text)
                .setAutoCancel(true);

        Notification notification = builder.build();
        startForeground(1, notification);

    } else {

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(text)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setAutoCancel(true);

        Notification notification = builder.build();

        startForeground(1, notification);
    }
    return START_NOT_STICKY;
}

Hinweis: Die Verwendung von Notification.Builder anstelle von NotificationCompat.Builder hat dazu geführt, dass es funktioniert. Nur in Notification.Builder müssen Sie die Kanal-ID angeben, eine neue Funktion in Android Oreo.

Hoffe, es funktioniert!

35
Bikram Pandit

Rufen Sie in der Aktivität (oder in einem beliebigen Kontext, der den Vordergrunddienst startet) Folgendes auf:

Intent intent = new Intent(this, MyService.class)
ContextCompat.startForegroundService(context, intent);

Wenn der Dienst gestartet wurde, erstellen Sie einen Benachrichtigungskanal mit ähnlichem Code wie Android-Dokumente . Erstellen Sie dann einen Build und verwenden Sie ihn:

final Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID).setSmallIcon(...)//
            .setPriority(...).setCategory(...).setContentTitle(...).setContentText(...).setTicker(...);
// and maybe other preparations to the notification...
startForeground(notificationId, builder.build());
5

Normalerweise starten Sie Ihren Dienst von einem Rundfunkempfänger mit startService. Sie sagen, dass es nicht mehr möglich (oder zuverlässig) ist, startService aufzurufen, da es jetzt Hintergrundbeschränkungen gibt. Sie müssen stattdessen startServiceInForeground aufrufen. Aus Dokumenten ist jedoch nicht wirklich klar, wann dies passiert, weil die App beim Empfang einer Broadcast-Absicht in die Positivliste aufgenommen wird. Daher ist nicht genau bekannt, wann startServiceIllegalStateException wirft.

5
greywolf82

Die ältere Methode zum Starten eines Vordergrunddiensts funktioniert immer noch, wenn sich die App im Vordergrund befindet. Die empfohlene Methode zum Starten eines Vordergrunddiensts für Apps, die API 26/Android O verwenden, ist die Verwendung der neu eingeführten NotificationManager # startServiceInForeground-Methode zum Erstellen eines Vordergrunddiensts an erster Stelle.

Die alte Methode, den Dienst im Hintergrund zu starten und dann in den Vordergrund zu bringen, funktioniert nicht, wenn sich die App im Hintergrundmodus befindet, da Android O im Hintergrund ausgeführt wird.

Der Migrationsprozess und die Schritte werden hier dokumentiert. https://developer.Android.com/preview/features/background.html#migration

3
balendran

Wie auch @Kislingk in einem Kommentar erwähnt, wurde NotificationManager.startServiceInForeground entfernt. Es wurde als veraltet mit dem Commit 08992ac markiert.

Aus der Commit-Nachricht:

Anstatt eine a-priori-Benachrichtigung zu verlangen, werden Starten Sie einen Dienst direkt in den Vordergrundzustand, übernehmen wir eine zweistufige Mischbetrieb für laufende Servicearbeiten auch von einem Hintergrundausführungszustand. Kontext # startForegroundService () ist nicht Hintergrundbeschränkungen unterliegen, mit der Anforderung, dass die Der Dienst gibt den Vordergrundzustand formal über startForeground () in .__ ein. 5 Sekunden. Wenn der Dienst dies nicht tut, wird er vom Betriebssystem und von .__ angehalten. Die App wird mit einem Dienst ANR beschuldigt.

2
einsA

startForeground (1, Benachrichtigung); funktioniert für Android O, aber gemäß Android O-Anforderung müssen wir dem Benutzer eine permanente Benachrichtigung anzeigen. Gleichzeitig kann es den Benutzer in einigen Fällen verwirren (Systembenachrichtigung über im Hintergrund ausgeführte App und Auswirkungen auf die Batterie), sodass der Benutzer die App deinstallieren kann. Am besten wäre es also, die WorkManager-Klasse neu einzuführen, um die Aufgabe als Vordergrund zu planen.

  1. Erstellen Sie Ihre Arbeiterklasse (z. B. MyWorker), indem Sie die Klasse "Worker" erweitern, in der Sie die lang andauernde Aufgabe ausführen können. Überschreiben Sie die folgende Methode in dieser Klasse:
    • doWork () [Erforderlich]
    • onStopped () [Optional]
    • onWorkFinished [Optional] etc.
  2. Erstellen Sie sich wiederholende/periodische [PeriodicWorkRequest] - oder nicht wiederholende [OneTimeWorkRequest] -Arbeiten Sie nach Bedarf.
  3. Rufen Sie die Instanz von WorkManager ab und stellen Sie die Arbeit in die Warteschlange.

Code-Auszug:

OneTimeWorkRequest work =
     new OneTimeWorkRequest.Builder(MyWorker.class)
 .build();
WorkManager.getInstance().enqueue(work);    
0
Akki

Ich füge ein Muster hinzu, wenn ein Bedarf mit Backstack Builder besteht

    val notifyManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
    val playIntent    = Intent(this, this::class.Java).setAction(PAUSE)
    val cancelIntent  = Intent(this, this::class.Java).setAction(EXIT)

    val stop          = PendingIntent.getService(this, 1, playIntent, PendingIntent.FLAG_UPDATE_CURRENT)
    val exit          = PendingIntent.getService(this, 2, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT)

    val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        notifyManager.createNotificationChannel(NotificationChannel(NOTIFICATION_ID_CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH))
        NotificationCompat.Builder(this, NOTIFICATION_ID_CHANNEL_ID)
    } else
        NotificationCompat.Builder(this)

    builder.apply {
        setContentTitle(station.name)
        setContentText(metaToText(meta) )
        setSmallIcon(R.drawable.ic_play_arrow_white_24px)
        setAutoCancel(false)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) priority = Notification.PRIORITY_MAX
        addAction(R.drawable.ic_stop_white_24px, getString(R.string.player_notification_stop), stop)
        addAction(R.drawable.ic_close_white_24px, getString(R.string.player_notification_exit), exit)
    }

    val stackBuilder = TaskStackBuilder.create(this)
    stackBuilder.addParentStack(PlayerActivity::class.Java)
    stackBuilder.addNextIntent(Intent(this, PlayerActivity::class.Java))
    builder.setContentIntent(stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT))

    startForeground(NOTIFICATION_ID, builder.build())
0
pavol.franek