WebView führt Webinhalte in einem separaten Renderer-Prozess aus. Manchmal kann dieser Prozess beendet werden. Das passiert, wenn das System den Renderer beendet, um Arbeitsspeicher freizugeben, oder wenn der Prozess selbst abstürzt. Wenn Sie diese Beendigungen nicht verarbeiten, wird auch Ihre Anwendung beendet.
Warum die Verarbeitung von Prozessbeendigungen wichtig ist
Bei älteren Android-Versionen war es weniger wahrscheinlich, dass Nutzer ein Problem bemerkten, wenn eine App die Beendigung des Renderer-Prozesses nicht verarbeitete. Neuere Android-Versionen verwenden jedoch komplexere Mechanismen, um den Ressourcenverbrauch von Hintergrundprozessen zu verwalten. Wenn Ihre App keinen Handler für onRenderProcessGone implementiert, ist es jetzt wahrscheinlicher, dass Nutzer sichtbare Beendigungen im Vordergrund bemerken, wenn sie zur App zurückkehren. Die Implementierung der Termination Handling API ist erforderlich, damit Ihre App ordnungsgemäß wiederhergestellt wird und eine stabile Nutzererfahrung bietet.
Termination Handling API verwenden
Sie können diese Situationen bewältigen, indem Sie onRenderProcessGone in Ihrer WebViewClient überschreiben.
Wichtige Anforderungen für die Wiederherstellung
Damit Ihre App nach dem Beenden eines Renderer-Prozesses weiter ausgeführt wird, muss jede WebView in Ihrer App die folgenden Regeln einhalten:
- Verwenden Sie die WebView-Instanz nicht wieder. Sobald der Renderer nicht mehr vorhanden ist, ist das entsprechende WebView-Objekt unbrauchbar. Sie müssen das WebView-Objekt aus der Ansichtshierarchie entfernen, es löschen und alle Verweise darauf in Ihrer Aktivität oder Ihrem Fragment löschen, um zu vermeiden, dass versehentlich weiterhin Methoden für die gelöschte WebView-Instanz aufgerufen werden.
- Neue Instanz erstellen Wenn Sie weiterhin Webinhalte anzeigen möchten, benötigen Sie eine neue WebView-Instanz.
- Gibt „true“ zurück. Ihre Implementierung muss
truezurückgeben, um dem WebView-Code mitzuteilen, dass Sie die Situation verarbeitet haben. Wenn eineWebView, die diesen Renderer-Prozess verwendet, nichttruezurückgibt, beendet WebView die App oder lässt sie abstürzen, je nach Grund für das Beenden des Renderer-Prozesses.
Implementierungsbeispiel
Das folgende Beispiel zeigt, wie diese Beendigungen innerhalb einer vollständigen Aktivität verarbeitet werden. Mit detail.didCrash() wird protokolliert, ob der Prozess abgestürzt ist oder ob das System den Renderer beendet hat, um Speicher freizugeben. Unabhängig von der Ursache wird der Code bereinigt, indem die nicht mehr funktionierende WebView aus dem Layout entfernt, zerstört und die Verweise der Aktivität gelöscht werden, um NullPointerException zu verhindern.
Anschließend wird eine neue Instanz vorbereitet und true zurückgegeben, damit die App nicht geschlossen wird.
Hinweis:Im folgenden Beispiel wird immer true zurückgegeben, damit die App weiter ausgeführt wird.
Wenn Sie möchten, dass Ihre App beendet wird, wenn der WebView-Renderer beendet wird, können Sie false von diesem Callback zurückgeben. Wir empfehlen jedoch, die Neuerstellung zu verarbeiten und true zurückzugeben, um eine stabile Nutzererfahrung zu gewährleisten.
class MyWebViewActivity : AppCompatActivity() {
private var webViewContainer: ViewGroup? = null
private var myWebView: WebView? = null
private var crashCount = 0
private val MAX_CRASHES = 3
// NEW FLAG: Tracks if the WebView crashed while the activity was hidden
private var isWebViewPendingRecovery = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my_web_view)
webViewContainer = findViewById(R.id.my_web_view_container)
initWebView()
}
// NEW LIFECYCLE HOOK: Triggers when the user brings the app back to the foreground
override fun onResume() {
super.onResume()
// If a crash happened in the background, rebuild it now that the user can see it
if (isWebViewPendingRecovery) {
isWebViewPendingRecovery = false
Log.i("MY_APP_TAG", "Activity resumed. Recovering pending WebView now.")
recoverWebView()
}
}
private fun initWebView() {
val webView = WebView(this)
myWebView = webView
webViewContainer?.addView(webView)
webView.webViewClient = object : WebViewClient() {
override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean {
if (detail.didCrash()) {
Log.e("MY_APP_TAG", "The WebView rendering process crashed!")
} else {
Log.e("MY_APP_TAG", "System killed the WebView rendering process to reclaim memory.")
}
// Safely clean up the dead WebView
webViewContainer?.removeView(webView)
webView.destroy()
myWebView = null
// MODIFIED LOGIC: Check the lifecycle state of the Activity
// lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) means the activity is visible and active
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
Log.i("MY_APP_TAG", "Activity is in foreground. Recovering immediately.")
recoverWebView()
} else {
// The app is in the background. Mark it for later!
Log.w("MY_APP_TAG", "Activity is in background. Postponing recovery until user returns.")
isWebViewPendingRecovery = true
}
return true
}
}
webView.loadUrl("https://www.example.com")
}
// HELPER FUNCTION: Extracted the recovery logic to reuse it
private fun recoverWebView() {
if (crashCount < MAX_CRASHES) {
crashCount++
Log.w("MY_APP_TAG", "Recovering WebView... Attempt $crashCount")
initWebView()
} else {
Log.e("MY_APP_TAG", "WebView crashed too many times. Showing error UI.")
showErrorUI()
}
}
private fun showErrorUI() {
// Example: Inflate an error view
}
override fun onDestroy() {
super.onDestroy()
myWebView?.let {
webViewContainer?.removeView(it)
it.destroy()
}
myWebView = null
}
}
Wichtige Aspekte
Beachten Sie bei der Implementierung von onRenderProcessGone die folgenden Punkte, um die Stabilität der App zu gewährleisten und die Sichtbarkeit von Beendigungsereignissen aufrechtzuerhalten:
- Wiederholte Abstürze:Wenn ein Renderer beim Laden einer bestimmten Seite abstürzt, lade nicht sofort dieselbe Seite noch einmal. Dies kann dazu führen, dass die neue WebView wieder abstürzt.
- Sichtbarkeit:App-Beendigungen, die durch das Fehlen dieses Callbacks verursacht werden, werden noch nicht in den Absturzberichten der Play Console berücksichtigt. Zukünftige Updates können diese Lücke zwar schließen, Sie müssen diese Probleme jedoch jetzt beheben, um die Stabilität der App zu gewährleisten. Wenn Sie diesen Handler implementieren, sehen Sie sofort, warum Ihre App beendet wird.
- Unterscheidung zwischen Beendigung des Renderers und Prozessbeendigung der App:
onRenderProcessGoneverarbeitet Situationen, in denen der Renderer-Prozess beendet wird, während der App-Prozess aktiv bleibt. Wenn der gesamte App-Prozess im Hintergrund vom System beendet wird, verwenden SieonSaveInstanceState()mitWebView.saveState()undWebView.restoreState(), um den Navigationsverlauf beizubehalten und wiederherzustellen. Informationen zum sicheren Verwalten des gespeicherten Status, ohne Transaktionslimits zu erreichen, finden Sie unter WebView-Status effizient verwalten.