O WebView executa o conteúdo da Web em um processo de renderização separado. Às vezes, esse processo pode ser encerrado. Isso acontece se o sistema interromper o renderizador para recuperar a memória ou se o próprio processo falhar. Se você não processar essas finalizações, o app também será encerrado.
Por que o tratamento do encerramento de processos é essencial
Em versões mais antigas do Android, era menos provável que os usuários percebessem um problema quando um
app não processava o encerramento do processo de renderização. No entanto, as versões mais recentes do
Android usam mecanismos mais complexos para gerenciar o consumo de recursos dos
processos em segundo plano. Consequentemente, se o app não implementar um manipulador para
onRenderProcessGone, agora é mais provável que os usuários observem encerramentos
visíveis em primeiro plano ao retornar ao app. A implementação da API de
processamento de encerramento é necessária para garantir que o app se recupere normalmente e mantenha uma
experiência do usuário estável.
Usar a API Termination Handling
Para lidar com essas situações, substitua onRenderProcessGone no seu
WebViewClient.
Principais requisitos para a recuperação
Para manter o app em execução após o encerramento de um processo de renderização, cada WebView no app precisa seguir estas regras:
- Não reutilize a instância do WebView. Depois que o renderizador desaparece, esse objeto WebView específico não tem mais utilidade. Remova o objeto WebView da hierarquia de visualização, destrua-o e limpe todas as referências a ele na sua atividade ou fragmento para evitar continuar chamando métodos acidentalmente na instância destruída do WebView.
- Crie uma instância. Se quiser continuar mostrando conteúdo da Web, você precisa de uma nova instância do WebView.
- Retorne "true". Sua implementação precisa retornar
truepara informar ao código WebView que você resolveu a situação. Se algumWebViewque usa esse processo de renderização não retornartrue, o WebView vai encerrar ou travar o app de acordo com o motivo de saída do processo de renderização.
Exemplo de implementação
O exemplo a seguir mostra como processar essas finalizações em uma
atividade completa. Ele usa detail.didCrash() para registrar se o processo falhou ou se
o sistema encerrou o renderizador para recuperar a memória. Independente da causa, o
código limpa removendo a WebView inativa do layout, destruindo-a
e limpando as referências da atividade para evitar NullPointerException.
Em seguida, ele prepara uma nova instância e retorna true para que o app não seja fechado.
Observação:o exemplo a seguir sempre retorna true para manter o app em execução.
Se você quiser que o app seja encerrado quando o renderizador da WebView
for encerrado, retorne false desse callback. No entanto, recomendamos
processar a recriação e retornar true para uma experiência do usuário estável.
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
}
}
Considerações importantes
Ao implementar onRenderProcessGone, tenha em mente as seguintes considerações para garantir a estabilidade do app e manter a visibilidade dos eventos de encerramento:
- Travamentos repetidos:se um renderizador travar ao carregar uma página específica, não recarregue a mesma página imediatamente. Isso pode fazer com que a nova WebView falhe de novo.
- Visibilidade:as finalizações de apps causadas pela falta desse callback ainda não são refletidas nos relatórios de falhas do Play Console. Embora as atualizações futuras possam resolver essa lacuna, é necessário resolver esses problemas agora para garantir a estabilidade do app. A implementação desse processador oferece visibilidade imediata sobre o motivo da saída do app.