安卓导航组件不停重新加载WebView

8
今天我在使用Android Navigation Component时,在Fragment中的WebView遇到了问题。 在我的情况下,在Fragment1中,有一个放置在WebView下方的按钮。用户需要向下滚动才能点击它。点击后,会打开一个新的目标(Fragment2)。然后,当用户返回到Fragment1时,WebView会重新加载,并且视口会再次滚动到顶部。
这太烦人了。用户可能已经向下滚动了几分钟,但每次回来后都被抛到了最上面。我能否防止它重新加载/滚动到顶部?
示例代码可以如下所示:
class Fragment1 : Fragment() {

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    webView.loadData(getString(R.string.some_very_long_html), "text/html", "UTF-8")
    buttonBelowWebView.setOnClickListener {
      navigateToFragment2()
    }
  }

}

如果 WebView 包含视频,则加载可能需要长达 5 秒钟。这是非常糟糕的体验。
我尝试添加标志以仅加载一次,但从 Fragment2 返回时,WebView 是空的:
class Fragment1 : Fragment() {

  var loaded = false
  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    if(!loaded) {
      webView.loadData(getString(R.string.some_very_long_html), "text/html", "UTF-8")
      loaded = true
    }
  }

}

请注意,在实际应用中,我使用ViewModel并从rest api观察数据,但问题仍然存在。
另外,我提供的示例代码是用Kotlin编写的,但如果有Java解决方案,则也会感激不尽。
在从嵌套目标返回时,是否可能不重新加载WebView并重置滚动位置?

你正在使用 AndroidX 的 WebView 还是平台自带的? - Blundell
我正在使用 android.webkit.WebView。有没有 AndroidX 的替代品? - xinaiz
是的,我自己也是上周才了解到这个!https://developer.android.com/reference/androidx/webkit/WebViewCompat - Blundell
@Blundell 这不是一个视图,而是一个帮助类,对吧? - xinaiz
@xinaiz,你试过我的解决方案了吗? - patel dhaval r
显示剩余3条评论
5个回答

11
这是片段在其基本形式下的工作方式(这是导航组件使用的方式)。
片段本身被保存,但它们的视图被销毁。
这是您的情况发生的情况:
- 片段1创建 - 片段1视图创建(其中包含Web视图) - 单击按钮 - 片段1视图被销毁 - 片段2创建 - 片段2视图创建 - 单击返回 - 片段1视图重新创建 - 片段2视图被销毁 - 片段2被销毁
如果您没有使用导航组件,那么使用非hacky方法解决这个问题将非常容易。您可以简单地在FragmentTransaction上使用.hide()和.add(),而不是.replace(),这样片段视图就不会被销毁。
但是,既然您正在使用导航组件,那么您不需要自己处理片段事务。
一种解决方法是在此处发布的方法: https://dev59.com/1FQJ5IYBdhLWcg3wGB5N#55039009 由于片段及其变量已保存,因此您可以将视图保存为片段中的变量。然后在onCreateView中检查变量是否为null,如果为null,则像通常一样膨胀它,如果不为null,则返回保存的视图。

谢谢!那正是我最终所做的!虽然我不确定这是否是一个好的解决方案。我有空的时候会将其发布为答案。 - xinaiz

2

在切换片段之前使用此代码:

最初的回答:

if (getVisibleFragment() instanceof Fragment1){
      // do nothing
}else{
      // replace fragment
}


    public Fragment getVisibleFragment(){
                FragmentManager fragmentManager = getSupportFragmentManager();
                List<Fragment> fragments = fragmentManager.getFragments();
                if(fragments != null){
                    for(Fragment fragment : fragments){
                        if(fragment != null && fragment.isVisible())
                            return fragment;
                    }
                }
                return null;
    }

2
最初的回答
请修改此内容。
class Fragment1 : Fragment() {

 @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    webView?.loadData(getString(R.string.some_very_long_html), "text/html", "UTF8")
   }

}

最初的回答

试一试


2
尝试这样做 - 这将在具有Web视图的片段中实现。 "Original Answer" 的意思是 "最初的回答"。
 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    if (view == null) {
        // inflate your layout here
        return view = inflater.inflate(R.layout.community_home_layout, container, false);
     }else {
      return view;
  }

1

无论您是第一次进入片段还是回来,其方法onViewCreated总是会再次调用,如果您想要像这样的东西,即您不想重置,可以通过一个全局布尔检查来实现,因为该全局变量在片段恢复后不会更改

就像这样

var shouldLoad = true

然后你想做什么就做什么

if(shouldLoad){
  //do your work

  //setting false to your boolean
  shouldLoad = false
}else{
  //if you need something else
}

不幸的是,如果我这样做,当我返回时webView是空的。当我回来时会调用'onCreateView',因此会充气新的布局,因此“新”的webView是空的。 - xinaiz
这不起作用,因为onCreateView被调用并且视图被膨胀,如果需要更多细节,请添加。 - Chris Herbst

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接