Ich bin auf ein Verhalten im Prozessmanagement von Android in Verbindung mit Vordergrunddiensten gestoßen, das mich wirklich verwirrt.
Was ist für mich vernünftig
- Wenn Sie Ihre App von "Letzte Apps" streichen, sollte das Betriebssystem den App-Prozess in relativ naher Zukunft beenden.
- Wenn Sie Ihre App von "Letzte Apps" wischen, während Sie einen Vordergrunddienst ausführen, bleibt die App am Leben.
- Wenn Sie den Vordergrunddienst beenden, bevor Sie Ihre App von "Letzte Apps" wischen, erhalten Sie dasselbe wie für 1).
Was mich verwirrt
Wenn Sie den Vordergrunddienst beenden, während keine Aktivitäten im Vordergrund sind (App wird NICHT in "Letzte Apps" angezeigt), würde ich erwarten, dass die App jetzt beendet wird.
Dies geschieht jedoch nicht, der App-Prozess ist noch am Leben.
Beispiel
Ich habe ein minimales Beispiel erstellt, das dieses Verhalten zeigt.
Der ForegroundService:
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import timber.log.Timber
class MyService : Service() {
override fun onBind(intent: Intent?): IBinder? = null
override fun onCreate() {
super.onCreate()
Timber.d("onCreate")
}
override fun onDestroy() {
super.onDestroy()
Timber.d("onDestroy")
// just to make sure the service really stops
stopForeground(true)
stopSelf()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Timber.d("onStartCommand")
startForeground(ID, serviceNotification())
return START_NOT_STICKY
}
private fun serviceNotification(): Notification {
createChannel()
val stopServiceIntent = PendingIntent.getBroadcast(
this,
0,
Intent(this, StopServiceReceiver::class.java),
PendingIntent.FLAG_UPDATE_CURRENT
)
return NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("This is my service")
.setContentText("It runs as a foreground service.")
.addAction(0, "Stop", stopServiceIntent)
.build()
}
private fun createChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(
NotificationChannel(
CHANNEL_ID,
"Test channel",
NotificationManager.IMPORTANCE_DEFAULT
)
)
}
}
companion object {
private const val ID = 532207
private const val CHANNEL_ID = "test_channel"
fun newIntent(context: Context) = Intent(context, MyService::class.java)
}
}
Der BroadcastReceiver, um den Dienst zu beenden:
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
class StopServiceReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val serviceIntent = MyService.newIntent(context)
context.stopService(serviceIntent)
}
}
Die Aktivität:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startService(MyService.newIntent(this))
}
}
Das Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.christophlutz.processlifecycletest">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService"/>
<receiver android:name=".StopServiceReceiver" />
</application>
</manifest>
Probieren Sie es folgendermaßen aus:
- App starten, Vordergrunddienst beenden, App aus 'Letzte Apps' entfernen
- App starten, App aus 'Letzte Apps' entfernen, Vordergrunddienst beenden
Sie können in LogCat von Android Studio sehen, dass der App-Prozess für Fall 1 mit [DEAD] markiert ist, für Fall 2 jedoch nicht.
Da es ziemlich einfach zu reproduzieren ist, könnte es sich um ein beabsichtigtes Verhalten handeln, aber ich habe in den Dokumenten keine wirkliche Erwähnung gefunden.
Weiß jemand, was hier los ist?
onDestroy
(Service) wird aufgerufen, aber der Prozess bleibt lange am Leben, nachdem alles weg ist. Selbst wenn das Betriebssystem den Prozess für den Fall, dass der Dienst neu gestartet wird, am Leben erhalten hat, verstehe ich nicht, warum es nicht dasselbe tut, wenn Sie den Dienst zuerst beenden und dann die App aus den letzten Jahren entfernen. Das angezeigte Verhalten scheint eher unintuitiv zu sein, insbesondere angesichts der jüngsten Änderungen der Ausführungsbeschränkungen im Hintergrund.