Хранение состояний переписчика в фрагменте с библиотекой подкачки и компонентом архитектуры навигации - PullRequest
0 голосов
/ 10 января 2019

Я использую 2 компонента джетпака: библиотека подкачки и навигация.

В моем случае у меня есть 2 фрагмента: ListMoviesFragment и MovieDetailFragment

когда я прокручиваю определенное расстояние и щелкаю по элементу фильма в обзоре переработчика, MovieDetailFragment присоединяется, а ListMoviesFragment находится в backstack. Затем я нажимаю кнопку «Назад», фрагмент ListMovies возвращается из backstack.

Точка - это прокручиваемая позиция, и элементы ListMoviesFrament сбрасываются точно так же, как при первом подключении к его активности. Итак, как сохранить состояние переработчика, чтобы предотвратить это?

Иными словами, как сохранить состояния целого фрагмента, например скрыть / показать фрагмент с FragmentTransaction традиционным способом, но для современного (навигация)

Мои образцы кодов:

фрагмент макета:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         tools:context="net.karaokestar.app.SplashFragment">

<TextView
        android:id="@+id/singer_label"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="Ca sĩ"
        android:textColor="@android:color/white"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/btn_game_more"
        android:layout_centerVertical="true"
        android:background="@drawable/shape_label"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="@dimen/header_margin_bottom_list"
        android:textStyle="bold"
        android:padding="@dimen/header_padding_size"
        android:textAllCaps="true"/>


<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list_singers"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

Фрагмент кода котлина:

    package net.karaokestar.app
    import android.os.Bundle
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import androidx.fragment.app.Fragment
    import androidx.lifecycle.LiveData
    import androidx.lifecycle.Observer
    import androidx.navigation.fragment.findNavController
    import androidx.paging.LivePagedListBuilder
    import androidx.paging.PagedList
    import androidx.recyclerview.widget.LinearLayoutManager
    import kotlinx.android.synthetic.main.fragment_splash.*
    import net.karaokestar.app.home.HomeSingersAdapter
    import net.karaokestar.app.home.HomeSingersRepository

    class SplashFragment : Fragment() {

        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.fragment_splash, container, false)
        }

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            val singersAdapter = HomeSingersAdapter()
            singersAdapter.setOnItemClickListener{
findNavController().navigate(SplashFragmentDirections.actionSplashFragmentToSingerFragment2())
}
            list_singers.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
            list_singers.setHasFixedSize(true)
            list_singers.adapter = singersAdapter

            getSingersPagination().observe(viewLifecycleOwner, Observer {
                singersAdapter.submitList(it)
            })
        }

        fun getSingersPagination() : LiveData<PagedList<Singer>> {
            val repository = HomeSingersRepository()
            val pagedListConfig = PagedList.Config.Builder().setEnablePlaceholders(true)
                .setPageSize(Configurations.SINGERS_PAGE_SIZE).setPrefetchDistance(Configurations.SINGERS_PAGE_SIZE).build()

            return LivePagedListBuilder(repository, pagedListConfig).build()
        }
    }

Ответы [ 4 ]

0 голосов
/ 04 июля 2019

Что нужно учитывать при решении следующих вопросов:

  1. Чтобы позволить ОС автоматически обрабатывать восстановление состояния представления, вы должны указать идентификатор. Я считаю, что это не так (потому что вы должны идентифицировать RecyclerView для привязки данных).

  2. Вы должны использовать правильный FragmentManager. У меня была та же проблема с вложенным фрагментом, и все, что мне нужно было сделать, это использовать ChildFragmentManager.

  3. SaveInstanceState () запускается действием. Пока активность жива, она не будет вызываться.

  4. Вы можете использовать ViewModels для сохранения состояния и восстановления его в onViewCreated ()

Наконец, контроллер навигации создает новый экземпляр фрагмента каждый раз, когда мы перемещаемся к месту назначения. Очевидно, что это плохо работает с сохранением постоянного состояния. Пока не будет официального исправления, вы можете проверить следующий обходной путь, который поддерживает присоединение / отсоединение, а также различные backstacks для каждой вкладки. Даже если вы не используете BottomNavigationView, вы можете использовать его для реализации механизма присоединения / отсоединения.

https://github.com/googlesamples/android-architecture-components/blob/27c4045aa0e40d402bbbde16d7ae0c9822a34447/NavigationAdvancedSample/app/src/main/java/com/example/android/navigationadvancedsample/NavigationExtensions.kt

0 голосов
/ 10 января 2019

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

В примере кода фактическая навигация (транзакция фрагмента) скрыта за этой строкой:

findNavController().navigate(SplashFragmentDirections.actionSplashFragmentToSingerFragment2())

Ключ заключается в том, как прикрепляется фрагмент сведений.

Исходя из вашего описания, ваш фрагмент данных, вероятно, прикреплен с FragmentTransaction.replace(int containerViewId, Fragment fragment). На самом деле, это сначала удалить текущий фрагмент списка, а затем добавить фрагмент детали в контейнер. В этом случае состояние фрагмента списка не сохраняется. При нажатии кнопки «Назад» фрагмент onViewCreated фрагмента списка снова запустится.

Чтобы сохранить состояние вашего фрагмента списка, вы должны использовать FragmentTransaction.add(int containerViewId, Fragment fragment) вместо replace. Таким образом, фрагмент списка остается там, где он есть, и он «покрывается» фрагментом детали. Когда вы нажимаете кнопку «назад», onViewCreated вызываться не будет, так как вид фрагмента не был уничтожен.

0 голосов
/ 10 января 2019

Поскольку вы используете NavController, вы не можете сохранять вид фрагмента списка при навигации.

Вместо этого вы можете сохранить данные RecyclerView и использовать эти данные при воссоздании представления после обратной навигации.

Проблема в том, что ваш адаптер и singersPagination создаются заново каждый раз, когда создается представление фрагмента. Вместо этого

  1. Переместить singersAdapter в поле:

    private val singersAdapter = HomeSingersAdapter()
    
  2. Переместить эту часть в onAttach

    getSingersPagination().observe(viewLifecycleOwner, Observer {
        singersAdapter.submitList(it)
    })
    
  3. Звоните retainInstance(true) в onAttach. Таким образом, даже изменения конфигурации не будут сбрасывать состояние.

0 голосов
/ 10 января 2019

На фрагменте onSaveinstanceState сохраните информацию о макете просмотра переработчика:

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putParcelable(KEY_LAYOUT, myRecyclerView.getLayoutManager().onSaveInstanceState());
    }

и onActivityCreated, восстановить позицию прокрутки:

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null) {
           myRecyclerView.getLayoutManager().onRestoreInstanceState(
                    savedInstanceState.getParcelable(KEY_LAYOUT));
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...