Navigation Component下Fragment中WebView状态保存失效求助
问题
使用Navigation Component从Home Fragment跳转到Web Fragment(代码中为TestFragment)加载指定URL,需求是离开Web Fragment时保存WebView状态,返回时恢复已保存状态而非重新加载页面,但当前实现无效。
当前代码:
public class TestFragment extends Fragment { private WebView webView; private Bundle webViewBundle; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.test_layout, container, false); webView = v.findViewById(R.id.webView); webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new MyWebViewClient()); if(webViewBundle != null){ webView.restoreState(webViewBundle); } else { assert getArguments() != null; String url = getArguments().getString("url"); webView.loadUrl(url); } return v; } @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); webView.restoreState(savedInstanceState); } @Override public void onPause() { super.onPause(); webViewBundle = new Bundle(); webView.saveState(webViewBundle); } class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { webView.loadUrl(url); webView.saveState(webViewBundle); return true; } } }
问题分析
- 状态存储位置错误:
webViewBundle是Fragment的成员变量,当Fragment被Navigation Component弹出栈销毁后,该变量会被回收,重建时无法获取之前保存的状态。 - 保存时机与方式错误:在
onPause中保存状态到成员变量,没有将状态存入Fragment的savedInstanceState,导致Fragment重建时状态丢失。 - 恢复逻辑混乱:
onCreateView中判断成员变量webViewBundle,但该变量在重建时为空;onViewStateRestored中直接用savedInstanceState恢复,但savedInstanceState中并未保存WebView状态。 - 不必要的手动保存:
shouldOverrideUrlLoading中调用saveState时,webViewBundle可能未初始化,会引发空指针异常,且页面加载过程中无需手动保存状态。
解决方案
将WebView状态存入Fragment的savedInstanceState,利用Fragment的生命周期方法正确保存和恢复状态:
- 移除自定义的
webViewBundle成员变量,改用系统提供的savedInstanceState存储状态。 - 在
onSaveInstanceState中保存WebView状态,这是Fragment销毁前系统会调用的方法,确保状态被持久化。 - 在
onCreateView中优先从savedInstanceState恢复状态,无状态时再加载初始URL。 - 修正
WebViewClient的逻辑,移除不必要的手动保存操作。
修改后的完整代码:
public class TestFragment extends Fragment { private WebView webView; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.test_layout, container, false); webView = v.findViewById(R.id.webView); // 初始化WebView基础设置 webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new MyWebViewClient()); // 优先恢复保存的状态,无状态则加载初始URL if (savedInstanceState != null) { webView.restoreState(savedInstanceState); } else { assert getArguments() != null; String url = getArguments().getString("url"); webView.loadUrl(url); } return v; } @Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); // 将WebView状态存入系统的savedInstanceState webView.saveState(outState); } class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // 让WebView内部处理跳转,无需手动保存状态 view.loadUrl(url); return true; } } }
额外说明
- Navigation Component中,当从Web Fragment返回Home Fragment时,Web Fragment会被销毁,再次跳转时会重建,此时
savedInstanceState会携带之前保存的状态,webView.restoreState会恢复到之前的页面位置、表单内容等状态。 - 确保WebView所在的布局中,WebView的id保持固定,避免状态恢复失败。
内容的提问来源于stack exchange,提问作者Taki
相关产品推荐
相关产品推荐

