You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Navigation Component处理WebView Fragment内游戏的暂停与状态保留

解决Navigation Component下Fragment C保持游戏暂停状态的问题

核心思路

默认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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 02:22:45