WebView esegue i contenuti web in un processo di rendering separato. A volte, questo processo può essere terminato. Ciò accade se il sistema interrompe il renderer per recuperare memoria o se il processo stesso si arresta in modo anomalo. Se non gestisci queste terminazioni, anche la tua app verrà chiusa.
Perché è fondamentale gestire la terminazione del processo
Nelle versioni precedenti di Android, era meno probabile che gli utenti notassero un problema quando un'app non riusciva a gestire la terminazione del processo di rendering. Tuttavia, le versioni più recenti di Android utilizzano meccanismi più complessi per gestire il consumo di risorse dei processi in background. Di conseguenza, se la tua app non implementa un gestore per
onRenderProcessGone, è ora più probabile che gli utenti osservino terminazioni visibili
in primo piano quando tornano all'app. L'implementazione dell'API Termination
Handling è necessaria per garantire che l'app si ripristini correttamente e mantenga un'esperienza utente
stabile.
Utilizzare l'API Termination Handling
Puoi gestire queste situazioni eseguendo l'override di onRenderProcessGone in WebViewClient.
Requisiti chiave per il ripristino
Per mantenere l'app in esecuzione dopo la terminazione di un processo di rendering, ogni WebView nella tua app deve rispettare queste regole:
- Non riutilizzare l'istanza WebView. Una volta che il renderer non è più disponibile, l'oggetto WebView specifico è inutile. Devi rimuovere l'oggetto WebView dalla gerarchia delle visualizzazioni, distruggerlo e cancellare tutti i riferimenti ad esso nella tua attività o nel tuo frammento per evitare di continuare accidentalmente a chiamare i metodi sull'istanza WebView distrutta.
- Crea una nuova istanza. Se vuoi continuare a mostrare contenuti web, hai bisogno di una nuova istanza WebView.
- Restituisci true. La tua implementazione deve restituire
trueper comunicare al codice WebView che hai gestito la situazione. Se unaWebViewche utilizza il processo di rendering non restituiscetrue, WebView interromperà o arresterà in modo anomalo l'app in corrispondenza del motivo di uscita del processo di rendering.
Esempio di implementazione
L'esempio seguente mostra come gestire queste terminazioni all'interno di un'attività completa. Utilizza detail.didCrash() per registrare se il processo si è arrestato in modo anomalo o se il sistema ha interrotto il renderer per recuperare memoria. Indipendentemente dalla causa, il
codice esegue la pulizia rimuovendo la WebView non funzionante dal layout, distruggendola,
e cancellando i riferimenti dell'attività per evitare NullPointerException.
Poi prepara una nuova istanza e restituisce true in modo che l'app non si chiuda.
Nota: l'esempio seguente restituisce sempre true per mantenere l'app in esecuzione.
Se vuoi che l'app venga chiusa quando il renderer WebView viene terminato, puoi restituire false da questo callback. Tuttavia, ti consigliamo di gestire la ricreazione e restituire true per un'esperienza utente stabile.
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
}
}
Considerazioni importanti
Quando implementi onRenderProcessGone, tieni presente le seguenti considerazioni per garantire la stabilità dell'app e mantenere la visibilità degli eventi di terminazione:
- Arresti anomali ripetuti: se un renderer si arresta in modo anomalo durante il caricamento di una pagina specifica, non ricaricare immediatamente la stessa pagina. Potrebbe causare un nuovo arresto anomalo di WebView.
- Visibilità: le chiusure dell'app causate dalla mancanza di questo callback non sono ancora riportate nei report sugli arresti anomali di Play Console. Sebbene i futuri aggiornamenti possano colmare questa lacuna, devi risolvere questi problemi ora per garantire la stabilità dell'app. L'implementazione di questo gestore fornisce una visibilità immediata del motivo per cui l'app viene chiusa.