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

Android TabLayout切换Fragment时如何保留WebView状态

问题原因

默认配合TabLayout使用的ViewPager/ViewPager2对Fragment的离屏保留阈值默认为1,即仅会缓存当前展示标签左右相邻各1个标签页的Fragment视图。当切换到间隔1个及以上的标签时,超出缓存范围的原标签Fragment会触发onDestroyView销毁视图层级,下次切回该标签时会重新执行onCreateView重建视图。
当前实现把WebView初始化、页面加载逻辑全部写在onCreateView生命周期中,视图重建时自然会触发WebView重新加载,丢失原有浏览状态。相邻标签切换不重载,刚好符合默认缓存阈值为1的表现。

具体实现步骤
  • 调整ViewPager离屏缓存数量
    在初始化ViewPager的代码中,将离屏缓存上限设置为「总标签数-1」,让所有标签页的Fragment视图常驻内存,不会因为切换被销毁,从根源上避免视图重建触发重载。
    在Activity/Fragment中初始化适配器后添加如下代码:
    // 总共有4个标签页,两侧各保留3个即可覆盖全部页面
    viewPager.offscreenPageLimit = 3
    
    如果使用ViewPager2,设置方法完全一致,同样调用setOffscreenPageLimit(3)即可。
  • 优化Fragment内WebView初始化逻辑
    避免每次视图重建都重复执行WebView配置、url加载操作,将WebView实例设为Fragment的成员变量,仅在首次初始化时执行加载逻辑。同时绑定Fragment生命周期处理WebView的销毁,避免内存泄漏。
    修正后的BrowseFragment代码如下:
    class BrowseFragment : Fragment() {
        private var webViewBrowse: WebView? = null
        private val targetUrl = "https://websitehome.page"
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            val myView = inflater.inflate(R.layout.fragment_browse, container, false)
            if (webViewBrowse == null) {
                webViewBrowse = myView.findViewById(R.id.webViewBrowse)
                webViewBrowse?.apply {
                    webViewClient = WebViewClient()
                    settings.javaScriptEnabled = true
                    loadUrl(targetUrl)
                }
            } else {
                // WebView已初始化时,从原有父布局移除后挂载到当前新创建的视图上
                (webViewBrowse?.parent as? ViewGroup)?.removeView(webViewBrowse)
                myView.addView(webViewBrowse)
            }
            return myView
        }
    
        override fun onDestroyView() {
            super.onDestroyView()
            // 视图销毁时不回收WebView实例,仅解除父布局挂载
            (webViewBrowse?.parent as? ViewGroup)?.removeView(webViewBrowse)
        }
    
        override fun onDestroy() {
            // Fragment彻底销毁时再回收WebView,避免内存泄漏
            webViewBrowse?.destroy()
            webViewBrowse = null
            super.onDestroy()
        }
    }
    
  • 修正PagerAdapter初始化参数
    原有FragmentPagerAdapter单参数构造方法已被废弃,传入正确的生命周期行为标记,避免Fragment生命周期调度异常:
    class SectionsPagerAdapter(private val context: Context, fm: FragmentManager) :
        FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
    
        override fun getItem(position: Int): Fragment {
            return when (position) {
                0 -> BrowseFragment()
                1 -> SecondFragment()
                2 -> ThirdFragment()
                3 -> FourthFragment()
                else -> BrowseFragment()
            }
        }
    
        override fun getPageTitle(position: Int): CharSequence? {
            return context.resources.getString(TAB_TITLES[position])
        }
    
        override fun getCount(): Int = 4
    }
    
补充说明

如果后续标签页数量增加、不适合将所有页面都加入离屏缓存,可以额外实现WebView的状态保存与恢复逻辑:在onSaveInstanceState中调用webView.saveState(bundle)保存浏览状态(包含滚动位置、表单内容、页面历史栈),切回重建时调用webView.restoreState(bundle)恢复状态即可,不需要重新加载url。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:15:11