ViewModel状態でのViewPager2 / Tabsの問題


9

私はMVVMパターンに従っています。つまり、フラグメントごとにViewModelがあります。

ViewPager2を使用して2つのタブを追加しました。

私のアダプターは次のようになります:

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

タブは機能しています。ただし、MergedItemsFragmentのViewModelの動作がおかしいことに気付きました。タブを追加する前に、次のようにFragmentに移動しました。

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

私がそのフラグメントを残しNavHostFragment.findNavController(this).popBackStack()、後でそのフラグメントに戻ったとき、新しい空のViewModelを取得します。これは意図されたものです。

新しいアプローチで私はナビゲートしていreturn new MergedItemsFragment()ます。そのフラグメントを離れると、後で戻ってきて、古いデータ含む ViewModelを取得しています。ユーザーが別のフラグメントで別のデータを選択したため、古いデータは関係なくなったため、これは問題です。


アップデート#1

同じprintステートメントが複数回呼び出されるため、彼は実際にはすべての古いFragmentをメモリに保持していることに気付きました。それが呼ばれる回数は、私が去ってその画面に戻る回数とともに増加します。したがって、10回離れて戻り、デバイスを回転させると、実際には1行が10回実行されます。ViewModelsで動作するように、ナビゲーションコンポーネントでTabs / ViewPagersを実装する方法を推測しますか?


アップデート#2

私は私のViewModelsを次のように設定しました:

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

私は同じ結果を得ます:

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

フラグメント自体にViewModelをバインドします。したがって、thisフラグメントです。


ViewModelの設定方法を教えていただけますか?また、新しいデータを取得したときに新しいViewModelを作成できない理由はありますか?
BlackHatSamurai

質問を更新しました。それ自身がそれを処理するビューモデルのポイントではありませんか?私はそれを1回作成し、それは1つのフラグメントの間持続します。新しいデータがある場合、どのように正確に再作成しますか?以前にそれを行う必要がなかったのはなぜですか?
user123456789

フラグメントが破壊されたため、以前はそれを行う必要がありませんでした。これでViewPagerが使用され、フラグメントがメモリに保存されます。必要なときにデータをクリアすることをお勧めします。VM自体ではなく、VM内のデータを管理する必要があります。
BlackHatSamurai

私が抱えている問題は、古いVMが実際にまだ古いLiveDataを提供し、他のコンポーネントに古いデータを供給していることです。したがって、古いVMが干渉し続けるため、データをクリアしても効果はありません。例:現在のViewModelのリストをクリアします。ただし、画面には引き続き古いリストが表示されます。ViewModelをデバッグして、リストの長さを確認すると、クリアされているため、0と表示されます。唯一の論理的な説明は、古いデータを提供する他のViewModelです。
user123456789

各フラグメントに同じVMを使用していますか?または、各フラグメントに独自のVMがありますか?
BlackHatSamurai

回答:


3

あなたのコメントによると、あなたはフラグメントを使用しており、そのフラグメントの中にビューページャーがあります。したがって、ViewPager用のアダプターを作成するときは、getActivity()の代わりにchildFragmentManagerを渡す必要があります。

以下は、使用できるviewPagerのサンプルアダプタです。

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]
    }
}

アダプタを作成している間に

   val adapter = NewViewPagerAdapter(
        childFragmentManager,
        FragmentPagerAdapter.POSITION_UNCHANGED
    )

FragmentStatePagerAdapterのドキュメントを参照しているかのように、アダプターのコンストラクター内で(FragmentManager、int)を渡す必要があることを示しています

いつか同じ問題に直面していたので、これで問題が解決することを願っています。

ハッピーコーディング。


1
ありがとう。ianhanniballakeがすでに言ったように、フラグメント自体を渡すだけで十分です。適切なコンストラクターがあることを確認してください。したがって、両方の回答が正しいです。
user123456789
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.