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?
quelle
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.getApplicationContext().startService(MyService.newIntent(this));
Sie es anstelle von dem, was Sie verwenden, und teilen Sie mir bitte die Ergebnisse mit. Ich glaube, die Aktivität bleibt am Leben, weil der Aktivitätskontext anstelle des Anwendungskontexts verwendet wird. Auch wenn Sie auf Oreo oder höher testen, versuchen Sie es mitgetApplicationContext().startforegroundService(MyService.newIntent(this));
Das Android-System ist bekannt für seine Selbsterkenntnis in Bezug auf Speicher, Prozessorleistung und Lebensdauer der Anwendungsprozesse. Es entscheidet selbst, ob ein Prozess beendet wird oder nicht (dasselbe gilt für Aktivitäten und Dienste).
Hier ist die offizielle Dokumentation zu diesem Thema.
Schauen Sie sich an, was in Bezug auf den Vordergrund steht
und sichtbare Prozesse (Foreground Service ist ein sichtbarer Prozess)
Dies bedeutet, dass auf dem Android-Betriebssystem Ihr App-Prozess ausgeführt wird, solange genügend Speicher vorhanden ist, um alle Vordergrundprozesse zu unterstützen. Selbst wenn Sie es stoppen, verschiebt das System es möglicherweise einfach in den Cache Prozesse und behandelt es in einer Warteschlange. Irgendwann wird es so oder so getötet - aber normalerweise liegt es nicht an Ihnen, sich zu entscheiden. Ehrlich gesagt sollte es Ihnen egal sein, was mit Ihrem App-Prozess passiert, nachdem (und solange) alle Android-Lebenszyklusmethoden aufgerufen wurden. Android weiß es besser.
Natürlich können Sie den Prozess mit beenden
android.os.Process.killProcess(android.os.Process.myPid());
aber es wird nicht empfohlen, da dies den ordnungsgemäßen Lebenszyklus von Android-Elementen stört und möglicherweise keine ordnungsgemäßen Rückrufe aufgerufen werden. Daher kann sich Ihre App in einigen Fällen schlecht verhalten.Ich hoffe es hilft.
quelle
Unter Android entscheidet das Betriebssystem, welche Anwendungen beendet werden.
Es gibt eine Prioritätsreihenfolge:
Anwendungen mit einem Vordergrunddienst werden selten beendet, stattdessen werden andere Apps und Dienste nach einer Zeit der Inaktivität beendet, und genau das passiert mit Ihrer App.
Wenn Sie den Vordergrunddienst beenden, erhöht dies die Wahrscheinlichkeit, dass das System Ihre App beendet. In keinem Fall bedeutet dies jedoch, dass sie sofort beendet wird.
quelle
Sie können mehrere Aktivitäten oder Aufgaben von einer einzigen App in der Liste haben. Es ist nicht eine Recent Apps - Liste.
Daher besteht keine direkte Korrelation zwischen den Elementen des Bildschirms "Letzte" und dem App-Prozess.
Jedenfalls , wenn Sie die letzte Aktivität der App zu schließen und haben nichts anderes im Prozess ausgeführt wird (wie ein Vordergrunddienst), der Prozess wird nur gereinigt.
Wenn Sie also einen laufenden Vordergrund stoppen (durch
stopService()
oderstopSelf()
und Aufheben der Bindung), bereinigt das System auch den Prozess, in dem es ausgeführt wurde.Es ist also in der Tat ein beabsichtigtes Verhalten .
quelle