Компонент навигации Android продолжает перезагружать WebView - PullRequest
5 голосов
/ 13 мая 2019

Сегодня я столкнулся с проблемой WebView внутри Fragment с использованием Android Navigation Component. В моем случае в 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 секунд. Это ужасный опыт.

Я пытался добавить флаг для загрузки только один раз, но затем WebView пуст при возврате из Fragment2:

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 s и наблюдаю данные из остальных API, но проблема остается той же.

Кроме того, пример кода, который я предоставил, написан на Kotlin, но если в Java есть решение, то оно также приветствуется.

Можно ли не перезагружать WebView и сбрасывать позицию прокрутки при переходе назад от вложенного пункта назначения?

Ответы [ 5 ]

7 голосов
/ 18 мая 2019

Вот как фрагменты работают в своей основной форме (именно это используют компоненты навигации)

Сами фрагменты сохраняются, но их представления уничтожаются.

Это то, что происходит вваш сценарий:

  • Создан фрагмент 1
  • Представление фрагмента 1 создано (содержит веб-представление)
  • Нажатие кнопки
  • Представление фрагмента 1 уничтожено
  • Фрагмент 2 создан
  • Фрагмент 2 создан вид
  • При нажатии назад
  • Фрагмент 1 вид создан заново
  • Фрагмент 2 вид уничтожен
  • Фрагмент 2 уничтожен

Если бы вы не использовали Навигационные компоненты, это было бы очень легко решить с помощью нехакерских способов.
Вы могли бы просто использовать .hide() в сочетании с.add() для FragmentTransaction вместо .replace(), и представления фрагментов не будут уничтожены.

Но поскольку вы используете компоненты навигации, вы сами не обрабатываете транзакции с фрагментами.

Обходной путь будет представлен здесь:
https://stackoverflow.com/a/55039009/2877453

Когда фрагмент и его переменные сохранены, вы можете сохранить свое представление как переменную во фрагменте.
Затем проверить в onCreateView, если переменная равна нулю, накачать ее как обычно, если не нулевую, а затем вернутьсохраненный вид.

2 голосов
/ 21 мая 2019

Попробуйте это -

это будет реализовано во фрагменте, который имеет веб-просмотр

 @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;
  }
2 голосов
/ 16 мая 2019

Пожалуйста, измените это

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 голосов
/ 16 мая 2019

Привет, когда вы впервые заходите во фрагмент или возвращаетесь к его методу onViewCreated, всегда вызывайте снова и снова, если вы хотите что-то похожее, не хотите сбрасывать, вы можете сделать это с помощью одной глобальной логической проверки, потому что эта глобальная переменнаяне изменится после возобновления фрагмента

Как это

var shouldLoad = true

И то, что вы хотите сделать

if(shouldLoad){
  //do your work

  //setting false to your boolean
  shouldLoad = false
}else{
  //if you need something else
}
2 голосов
/ 14 мая 2019

Используйте этот код перед изменением фрагмента: -

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;
    }
...