使用Navigation Component处理WebView Fragment内游戏的暂停与状态保留
核心思路
默认Navigation Component从Fragment C返回B时会销毁C,导致WebView和游戏状态丢失。解决关键是分离视图状态与游戏逻辑状态的保存恢复,用Activity级ViewModel持久化游戏状态,同时利用WebView自身机制恢复视图状态。
具体实现步骤
1. 创建共享ViewModel保存游戏状态
用Activity级ViewModel确保Fragment C销毁重建后状态不丢失:
class GameStateViewModel : ViewModel() { // 标记游戏是否处于暂停状态 var isGamePaused = false // 保存WebView的视图状态Bundle var webViewSavedState: Bundle? = null // 保存游戏业务进度(如关卡、分数,根据游戏实际定义) var gameProgress: String? = null }
2. 在Fragment C中处理状态的保存与恢复
在Fragment生命周期方法中结合ViewModel完成游戏暂停、状态保存和恢复:
class FragmentC : Fragment() { private lateinit var viewModel: GameStateViewModel private lateinit var gameWebView: WebView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 获取Activity级ViewModel,跨Fragment重建时状态保留 viewModel = ViewModelProvider(requireActivity())[GameStateViewModel::class.java] } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_c, container, false) gameWebView = view.findViewById(R.id.game_webview) // 初始化WebView基础配置 gameWebView.settings.apply { javaScriptEnabled = true domStorageEnabled = true } return view } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 恢复WebView视图状态 viewModel.webViewSavedState?.let { savedState -> gameWebView.restoreState(savedState) } ?: run { // 首次加载游戏页面 gameWebView.loadUrl("file:///android_asset/game.html") } // 恢复游戏暂停状态 if (viewModel.isGamePaused) { // 调用游戏JS接口暂停(需前端提供对应方法) gameWebView.evaluateJavascript("window.pauseGame()", null) } } override fun onPause() { super.onPause() // 暂停游戏 gameWebView.evaluateJavascript("window.pauseGame()", null) viewModel.isGamePaused = true // 保存WebView视图状态 val webViewState = Bundle() gameWebView.saveState(webViewState) viewModel.webViewSavedState = webViewState // 获取并保存游戏当前进度(需前端提供JS接口) gameWebView.evaluateJavascript("window.getCurrentProgress()") { progress -> viewModel.gameProgress = progress } } override fun onDestroyView() { // 销毁WebView避免内存泄漏,状态已通过ViewModel保存 gameWebView.destroy() super.onDestroyView() } }
3. 可选优化:开启Navigation状态自动保存
在导航图中给Fragment C设置android:saveEnabled="true",让Navigation自动保存Fragment视图状态,减少手动处理的工作量:
<fragment android:id="@+id/fragmentC" android:name="com.yourpackage.FragmentC" android:label="Fragment C" android:saveEnabled="true"> <action android:id="@+id/action_fragmentC_to_fragmentB" app:destination="@id/fragmentB" /> </fragment>
关键注意事项
- WebView的
saveState()/restoreState()仅能恢复页面基础状态(如滚动位置),游戏逻辑状态(暂停、关卡)必须通过ViewModel单独保存,再通过JS接口恢复。 - 需确保游戏前端提供对应的JS控制接口(如
pauseGame()、getCurrentProgress()),让Android端能调用控制游戏状态。 - 绝对不要将WebView实例存入ViewModel,会引发内存泄漏,仅保存状态Bundle即可。
内容的提问来源于stack exchange,提问作者ChanduGudimetla
相关产品推荐
相关产品推荐

