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

如何在Fragment中保存WebView的完整状态?

解决WebView完整状态保存问题

1. 核心问题分析

当前实现的问题在于:

  • 每次进入HomeFragment都会重新创建WebView实例,旧实例被销毁后,仅靠Bundle无法完整恢复滚动位置、视频进度这类运行时状态
  • saveState的时机和WebView的生命周期绑定逻辑有误,导致状态保存不完整
  • restoreState本身依赖WebView配置一致性,且仅靠Bundle无法替代WebView实例的持续存在

2. 具体解决方案

修改ViewModel:复用WebView实例

将WebView实例保存在ViewModel中,避免Fragment视图销毁时WebView被回收:

class WebViewModel : ViewModel() {
    var webView: CustomWebView? = null
    private val webViewState = Bundle()

    // 确保WebView仅初始化一次
    fun initWebView(context: Context): CustomWebView {
        return webView ?: run {
            CustomWebView(context).apply {
                // 配置WebView核心参数,必须和后续恢复时一致
                settings.javaScriptEnabled = true
                settings.domStorageEnabled = true
                settings.cacheMode = WebSettings.LOAD_DEFAULT
                settings.mediaPlaybackRequiresUserGesture = false
                webView = this
            }
        }
    }

    fun saveWebViewState() {
        webView?.saveState(webViewState)
    }

    fun restoreWebViewState() {
        webView?.restoreState(webViewState)
    }
}

修改HomeFragment:优化生命周期逻辑

在Fragment视图销毁时仅移除WebView而非销毁,返回时直接复用实例:

class HomeFragment : Fragment() {
    private lateinit var binding: FragmentHomeBinding
    private val viewModel: WebViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initWebView()
        setupBottomBarListeners()
    }

    private fun initWebView() {
        val webView = viewModel.initWebView(requireContext())
        // 避免重复添加WebView到布局
        if (webView.parent != null) {
            (webView.parent as ViewGroup).removeView(webView)
        }
        binding.frameLayout.addView(webView)

        // 首次加载默认页面
        if (webView.url == null) {
            webView.loadUrl("https://google.com")
        } else {
            viewModel.restoreWebViewState()
        }
    }

    private fun setupBottomBarListeners() {
        binding.apply {
            layoutBottomBar.rLTextBarContainer.setOnClickListener {
                showSearchFragment()
            }
            layoutBottomBar.ivBottomMenu.setOnClickListener {
                showBottomMenu()
            }
            layoutBottomBar.ivRefreshOrCancel.setOnClickListener {
                refreshOrCancelClicked()
            }
        }
    }

    override fun onPause() {
        super.onPause()
        viewModel.webView?.onPause()
        viewModel.saveWebViewState()
    }

    override fun onResume() {
        super.onResume()
        viewModel.webView?.onResume()
    }

    override fun onDestroyView() {
        // 仅移除WebView,不销毁实例
        binding.frameLayout.removeView(viewModel.webView)
        super.onDestroyView()
    }
}

3. 关键注意事项

  • 必须保证WebView的初始化配置(如JS启用、DOM存储、缓存模式)全程一致,否则restoreState会失效
  • 调用webView.onPause()/webView.onResume()可同步页面媒体播放状态,确保视频进度保留
  • 若自定义CustomWebView,不要重写saveState/restoreState方法,避免破坏原生逻辑

内容的提问来源于stack exchange,提问作者Waqas Younis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 01:54:13