Сохранение состояния вложенных фрагментов в ViewPager - PullRequest
0 голосов
/ 17 мая 2018

Итак, у меня есть активность с DrawerLayout. Я могу переключиться на Fragment1, который содержит TabLayout с тремя другими фрагментами (NestedFragment1, NestedFragment2, NestedFragment3). Я хочу иметь возможность сохранять данные в каждом NestedFragments, поскольку я делаю вызовы API внутри них. Я попытался переопределить onSaveInstanceState и сохранить данные, но SavedInstanceState всегда был нулевым.

Fragment1 код:

    class Fragment1 : Fragment() {
        private lateinit var viewPager: ViewPager
        private lateinit var tabLayout: TabLayout
        private lateinit var pagerAdapter: PagerAdapter

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            pagerAdapter = ForecastPagerAdapter(childFragmentManager)

        }

        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                                  savedInstanceState: Bundle?): View? {
            val view = inflater.inflate(R.layout.fragment_forecast, container, false)
            viewPager = view.findViewById(R.id.view_pager)
            viewPager.offscreenPageLimit = 3
            viewPager.adapter = pagerAdapter
            tabLayout = view.findViewById(R.id.tabs)
            tabLayout.setupWithViewPager(viewPager)
            return view
        }
}

Example of nested fragment code:

    class NestedFragment : Fragment() {

        private lateinit var recyclerView: RecyclerView
        private lateinit var recyclerViewAdapter: HourForecastAdapter
        private lateinit var swipeRefreshLayout: SwipeRefreshLayout

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            recyclerViewAdapter = HourForecastAdapter()


        }

        override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            val view = inflater!!.inflate(R.layout.fragment_day_forecast, container, false)

            swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_layout_hour)
            swipeRefreshLayout.apply {
                this.setOnRefreshListener {
                    performQuery()
                }
            }
            recyclerView = view.findViewById(R.id.recycler_view_hour_forecast)
            recyclerView.adapter = recyclerViewAdapter
            recyclerView.layoutManager = LinearLayoutManager(activity)


            return view
        }

 fun performQuery() {
        // ...

                    recyclerViewAdapter.forecastList = result.hourly.data
                    recyclerViewAdapter.notifyDataSetChanged()

    }
}

Я хочу сохранить forecastList (Список), который возвращается методом performQuery. Каждый раз, когда я переключаюсь на Фрагмент 1, все данные из вложенных фрагментов исчезают.

Этот код используется для переключения фрагментов:

navigationView.setNavigationItemSelectedListener {
                var fragment = when (it.itemId) {
                    R.id.nav_map -> Fragment0()
                    R.id.nav_forecast -> Fragment1()
                    R.id.nav_app_info -> Fragment2()
                    else -> Fragment1()
                }

                replaceFragment()

                it.isChecked = true
                drawerLayout.closeDrawers()
                true
            }
        }

Редактировать: добавлена ​​функция замены фрагмента:

fun replaceFragment(fragment: android.support.v4.app.Fragment){
        val fragmentName = fragment::class.java.simpleName
        val isFragmentInBackStack = fragmentManager.popBackStackImmediate(fragmentName, 0)
        if (!isFragmentInBackStack) {
            fragmentManager.beginTransaction()
                    .replace(R.id.main_activity_frame, fragment)
                    .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                    .addToBackStack(fragmentName)
                    .commit()
        }
    }

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Итак, мне удалось решить эту проблему с помощью фрагмента «кеширование»:

fun cacheFragment(fragment: android.support.v4.app.Fragment) {
        Log.d("Caching", "Working with ${fragment.javaClass.simpleName}")
        var findFragment = supportFragmentManager.findFragmentByTag(fragment.javaClass.simpleName)
        if (findFragment == null) {
            Log.d("Caching", "Creating new instance of ${fragment.javaClass.simpleName}")
            findFragment = fragment.javaClass.newInstance()
        }
        supportFragmentManager.beginTransaction()
                .replace(R.id.main_activity_frame, findFragment, fragment.javaClass.simpleName)
                .addToBackStack(null)
                .commit()
    }

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

0 голосов
/ 17 мая 2018

Во-первых, вам нужно позвонить .addToBackstack(null), прежде чем совершить транзакцию. Это также повлияет на вашу кнопку возврата. Смотрите # документация:

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

Почему это работает так? Ваше приложение не знает, что вы хотите открыть старый фрагмент вместо создания нового (потому что вы фактически запросили создание нового фрагмента). Кроме того, вы должны сообщить своему приложению: «Эй, вы! Не создавайте новый фрагмент, а извлекайте старый из backstack, если он есть».

Вы можете проверить, как это сделать, например. здесь: Как возобновить фрагмент из BackStack, если существует

PS: Хорошей практикой является создание фрагмента не конструктором, а статическим методом "getInstance (): Fragment".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...