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 encerrar o renderizador para recuperar memória ou se o próprio processo falhar. Se você não lidar com essas finalizações, seu app também será encerrado.
Por que o processamento do encerramento de processos é fundamental
Em versões anteriores do Android, era menos provável que os usuários percebessem um problema quando um
app não conseguia processar o encerramento do processo do renderizador. No entanto, as versões mais recentes do
Android usam mecanismos mais complexos para gerenciar o consumo de recursos de
processos em segundo plano. Consequentemente, se o app não implementar um gerenciador para
onRenderProcessGone, é mais provável que os usuários observem encerramentos visíveis
em primeiro plano ao retornar ao app. A implementação da API Termination
Handling é necessária para garantir que o app se recupere de forma adequada e mantenha uma
experiência do usuário estável.
Usar a API Termination Handling
Para lidar com essas situações, substitua onRenderProcessGone no
WebViewClient.
Principais requisitos para 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 da WebView. Depois que o renderizador é removido, esse objeto WebView específico se torna inútil. Remova o objeto WebView da hierarquia de visualização, destrua-o e limpe todas as referências a ele na atividade ou no fragmento para evitar que métodos continuem sendo chamados acidentalmente na instância de WebView destruída.
- Criar uma nova instância. Se você quiser continuar mostrando conteúdo da Web, precisará de uma nova instância de WebView.
- Retorna verdadeiro. Sua implementação precisa retornar
truepara informar ao código da WebView que você lidou com a situação. Se algumWebViewque usa esse processo de renderização não retornartrue, o WebView vai encerrar ou causar falhas no app de acordo com o motivo de saída do processo de renderização.
Exemplo de implementação
O exemplo a seguir mostra como lidar com essas finalizações em uma
Activity completa. Ele usa detail.didCrash() para registrar se o processo falhou ou se
o sistema encerrou o renderizador para recuperar memória. Independentemente da causa, o
código faz uma limpeza 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 do 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, considere o seguinte para garantir a estabilidade do app e manter a visibilidade dos eventos de encerramento:
- Falhas repetidas:se um renderizador falhar ao carregar uma página específica, não recarregue a mesma página imediatamente. Isso pode fazer com que o novo WebView falhe novamente.
- Visibilidade:as finalizações de apps causadas pela falta desse callback ainda não são refletidas nos relatórios de erros do Play Console. Embora as atualizações futuras possam resolver essa lacuna, você precisa resolver esses problemas agora para garantir a estabilidade do app. A implementação desse gerenciador oferece visibilidade imediata do motivo pelo qual o app é encerrado.
- Distinguir o encerramento do renderizador do encerramento do processo do app:o
onRenderProcessGonelida com situações em que o processo do renderizador é encerrado enquanto o processo do app permanece ativo. Se todo o processo do app for encerrado pelo sistema em segundo plano, useonSaveInstanceState()comWebView.saveState()eWebView.restoreState()para persistir e recuperar o histórico de navegação. Para gerenciar o estado salvo com segurança sem atingir os limites de transação, consulte Gerenciar o estado do WebView com eficiência.