Masalah ViewPager2 / Tab dengan kondisi ViewModel

9

Saya mengikuti pola MVVM - artinya saya memiliki ViewModel untuk setiap Fragmen.

Saya menambahkan dua tab dengan menggunakan ViewPager2.

Adaptor saya terlihat seperti ini:

@Override
public Fragment createFragment(int position) {
    switch (position) {
        case 0:
            return new MergedItemsFragment();
        case 1:     
            return new ValidatedMergedItemsFragment();
    }
    return new MergedItemsFragment();
}

Tab berfungsi. Namun, saya perhatikan bahwa ViewModel dari MergedItemsFragment saya berperilaku aneh. Sebelum saya menambahkan tab, saya menavigasi ke Fragmen seperti ini:

NavHostFragment.findNavController(this).navigate(R.id.action_roomFragment_to_itemsFragment);

Ketika saya meninggalkan fragmen itu NavHostFragment.findNavController(this).popBackStack()dan kemudian kembali ke fragmen itu, saya akan mendapatkan ViewModel kosong baru. Ini dimaksudkan.

Dengan pendekatan baru saya menavigasi return new MergedItemsFragment(). Ketika saya meninggalkan fragmen itu dan kemudian kembali saya mendapatkan ViewModel yang berisi data lama . Itu adalah masalah karena data lama tidak relevan lagi karena Pengguna memilih data yang berbeda di fragmen lain.


Perbarui # 1

Saya menyadari bahwa dia benar-benar menyimpan semua Fragmen lama di memori karena pernyataan cetak yang sama dipanggil beberapa kali. Waktu yang disebut meningkat dengan jumlah kali saya pergi dan kembali ke layar itu. Jadi jika saya pergi dan kembali 10 kali dan memutar perangkat saya dia benar-benar akan mengeksekusi satu baris 10 kali. Adakah tebakan bagaimana menerapkan Tab / ViewPagers dengan Komponen Navigasi dengan cara yang bekerja dengan ViewModels?


Perbarui # 2

Saya mengatur ViewModels saya seperti ini:

viewModel = new ViewModelProvider(this, providerFactory).get(MergedItemViewModel.class)

Saya mendapatkan hasil yang sama dengan:

viewModel = ViewModelProviders.of(this).get(MergedItemViewModel.class);

Saya mengikat ViewModel dalam Fragmen itu sendiri. Karena itu, thisadalah Fragmen.

pengguna123456789
sumber
Bisakah Anda menunjukkan bagaimana Anda mengatur ViewModels Anda? Juga, apakah ada alasan Anda tidak bisa hanya membuat ViewModel baru ketika Anda mendapatkan data baru?
BlackHatSamurai
Saya telah memperbarui pertanyaan saya. Bukankah poin dari model tampilan yang menangani itu sendiri? Saya membuatnya sekali dan itu bertahan untuk satu fragmen. Bagaimana tepatnya saya akan membuatnya kembali jika saya memiliki data baru dan mengapa saya tidak perlu melakukannya sebelumnya?
user123456789
Anda tidak perlu melakukannya sebelumnya karena fragmennya dihancurkan. Sekarang Anda menggunakan ViewPager dan menyimpan fragmen dalam memori. Saya sarankan hanya membersihkan data saat Anda perlu. Anda perlu mengelola data dalam VM, bukan VM itu sendiri.
BlackHatSamurai
Masalah yang saya miliki adalah bahwa VM lama sebenarnya masih melayani LiveData lama dan memberi makan data lama komponen lainnya. Jadi, membersihkan data tidak akan berhasil karena VM lama terus mengganggu. Contoh: Saya menghapus daftar di ViewModel saat ini. Namun layar masih mendapatkan daftar lama. Ketika saya men-debug ViewModel dan memeriksa panjang Daftar katanya 0 - karena sudah dihapus. Satu-satunya penjelasan logis adalah ViewModels lain yang menyajikan data lama.
user123456789
Apakah Anda menggunakan VM yang sama untuk masing-masing fragmen? Atau apakah setiap fragmen memiliki VM sendiri?
BlackHatSamurai

Jawaban:

3

Sesuai komentar Anda, Anda menggunakan Fragmen dan di dalam Fragmen itu ada viewpager Anda. Jadi saat membuat Adaptor untuk ViewPager, Anda harus melewati childFragmentManager alih-alih getActivity ()

Di bawah ini adalah contoh Adaptor untuk viewPager Anda yang dapat Anda gunakan

class NewViewPagerAdapter(fm: FragmentManager, behavior: Int) : FragmentStatePagerAdapter(fm, behavior) {
    private val mFragmentList: MutableList<Fragment> = ArrayList()
    private val mFragmentTitleList: MutableList<String> = ArrayList()

    override fun getItem(position: Int): Fragment {
        return mFragmentList[position]
    }

    override fun getCount(): Int {
        return mFragmentList.size
    }

    fun addFragment(fragment: Fragment, title: String) {
        mFragmentList.add(fragment)
        mFragmentTitleList.add(title)
    }

    override fun getPageTitle(position: Int): CharSequence? {
        return mFragmentTitleList[position]
    }
}

dan saat membuat adaptor Anda menyebutnya seperti

   val adapter = NewViewPagerAdapter(
        childFragmentManager,
        FragmentPagerAdapter.POSITION_UNCHANGED
    )

seolah-olah Anda melihat dokumentasi untuk FragmentStatePagerAdapter itu menyatakan bahwa Anda harus lulus (FragmentManager, int) di dalam konstruktor adaptor Anda

Saya harap ini akan menyelesaikan masalah Anda karena saya menghadapi masalah yang sama suatu hari nanti.

Selamat coding.

Rakshit Nawani
sumber
1
Terima kasih. Seperti yang ianhanniballake katakan, melewati fragmen itu sendiri sudah cukup, pastikan Anda memiliki konstruktor yang cocok. Jadi kedua jawaban itu benar.
user123456789