WebView запускает веб-контент в отдельном процессе отрисовки. Иногда этот процесс может быть прерван. Это происходит, если система завершает работу обработчика, чтобы освободить память, или если происходит сбой в самом процессе. Если вы не обработаете эти завершения, ваше приложение тоже закроется.
Почему важно обрабатывать завершение процесса
В более ранних версиях Android пользователи реже замечали проблемы, когда приложение не могло обработать завершение процесса визуализации. Однако в более новых версиях Android используются более сложные механизмы управления потреблением ресурсов фоновыми процессами. Если в вашем приложении не реализован обработчик для onRenderProcessGone, то при возвращении в приложение пользователи, скорее всего, увидят, что оно было закрыто. Чтобы приложение восстанавливалось без сбоев и работало стабильно, необходимо реализовать Termination Handling API.
Как использовать Termination Handling API
Чтобы обработать такие ситуации, переопределите метод onRenderProcessGone в классе WebViewClient.
Основные требования для восстановления
Чтобы приложение продолжало работать после завершения процесса визуализации, каждый компонент WebView в нем должен соответствовать следующим правилам:
- Не используйте экземпляр WebView повторно. После того как средство визуализации исчезнет, этот конкретный объект WebView станет бесполезным. Чтобы избежать случайных вызовов методов в удаленном экземпляре WebView, удалите объект WebView из иерархии View, уничтожьте его и очистите все ссылки на него в Activity или Fragment.
- Создайте новый экземпляр. Если вы хотите продолжить показ веб-контента, вам потребуется новый экземпляр WebView.
- Возвращает значение true. Ваша реализация должна возвращать
true, чтобы сообщить коду WebView, что вы обработали ситуацию. Если какой-либо объектWebView, использующий этот процесс визуализации, не возвращаетtrue, WebView завершит работу вашего приложения или вызовет его сбой в соответствии с причиной выхода из процесса визуализации.
Пример реализации
В примере ниже показано, как обрабатывать такие завершения в рамках полного действия. Для регистрации сбоев процесса или принудительного завершения отрисовки системой с целью освобождения памяти используется detail.didCrash(). Независимо от причины, код удаляет неработающий компонент WebView из макета, уничтожает его и очищает ссылки на действия, чтобы предотвратить NullPointerException.
Затем он подготавливает новый экземпляр и возвращает true, чтобы приложение не закрывалось.
Примечание. В примере ниже всегда возвращается значение true, чтобы приложение продолжало работать.
Если вы хотите, чтобы приложение закрывалось при завершении работы средства визуализации WebView, вы можете вернуть false из этого обратного вызова. Однако мы рекомендуем обрабатывать повторное создание и возвращать true, чтобы обеспечить стабильную работу приложения.
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
}
}
Важные примечания
При реализации onRenderProcessGone учитывайте следующие рекомендации, чтобы обеспечить стабильность приложения и отслеживать события завершения:
- Повторяющиеся сбои. Если при загрузке определенной страницы происходит сбой средства визуализации, не перезагружайте ее сразу. Это может привести к повторному сбою нового WebView.
- Видимость. Принудительные завершения работы приложения, вызванные отсутствием этого обратного вызова, пока не отражаются в отчетах о сбоях в Play Console. В будущих обновлениях эти проблемы могут быть устранены, но сейчас вам нужно решить их самостоятельно, чтобы обеспечить стабильность приложения. Реализация этого обработчика позволяет сразу понять, почему приложение закрывается.
- Различать завершение работы средства визуализации и процесса приложения.
onRenderProcessGoneобрабатывает ситуации, когда процесс средства визуализации завершается, а процесс приложения остается активным. Если система завершает весь процесс приложения в фоновом режиме, используйтеonSaveInstanceState()сWebView.saveState()иWebView.restoreState(), чтобы сохранить и восстановить историю навигации. Чтобы безопасно управлять сохраненным состоянием, не превышая лимиты транзакций, ознакомьтесь с разделом Эффективное управление состоянием WebView.