ViewModel 상태의 ViewPager2 / Tabs 문제


9

MVVM 패턴을 따르고 있습니다. 즉, 각 조각에 대해 ViewModel이 있습니다.

ViewPager2를 사용하여 두 개의 탭을 추가했습니다 .

내 어댑터는 다음과 같습니다

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

탭이 작동 중입니다. 그러나 MergedItemsFragment의 ViewModel이 이상하게 작동하는 것으로 나타났습니다. 탭을 추가하기 전에 다음과 같이 조각으로 이동했습니다.

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

그 조각을 남겨두고 NavHostFragment.findNavController(this).popBackStack()나중에 그 조각 으로 돌아 왔을 때 새로운 빈 ViewModel을 얻습니다. 이것은 의도 된 것입니다.

새로운 접근 방식으로 나는 탐색하고 return new MergedItemsFragment()있습니다. 해당 조각을 남겨두고 나중에 반환 하면 이전 데이터 가 포함 된 ViewModel이 나타납니다 . 사용자가 다른 조각에서 다른 데이터를 선택했기 때문에 이전 데이터는 더 이상 관련이 없기 때문에 문제가됩니다.


업데이트 # 1

나는 동일한 인쇄 문이 여러 번 호출되기 때문에 실제로 모든 이전 조각 을 메모리에 보관한다는 것을 깨달았 습니다. 호출 시간은 내가 떠나서 해당 화면으로 돌아 오는 횟수에 따라 증가합니다. 따라서 내가 10 번 떠났다가 내 장치를 돌리면 실제로 한 줄을 10 번 실행합니다. ViewModels와 작동하는 방식으로 탐색 구성 요소로 탭 / ViewPagers를 구현하는 방법이 있습니까?


업데이트 # 2

ViewModels를 다음과 같이 설정했습니다.

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

나는 같은 결과를 얻는다 :

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

Fragment 자체에서 ViewModel을 바인딩합니다. 따라서 this조각입니다.


ViewModel 설정 방법을 보여줄 수 있습니까? 또한 새로운 데이터를 가져올 때 새로운 ViewModel을 만들 수없는 이유가 있습니까?
— BlackHatSamurai

내 질문을 업데이트했습니다. 자체적으로 관리하는 뷰 모델의 요점이 아닌가? 한 번 만들고 하나의 조각에 대해 지속됩니다. 새 데이터가있는 경우 어떻게 정확하게 다시 작성합니까? 왜 이전에이를 수행하지 않아도됩니까?
— user123456789

프래그먼트가 파괴되었으므로 이전에 수행 할 필요가 없었습니다. 이제 ViewPager를 사용하고 있으며 조각을 메모리에 저장합니다. 필요할 때 데이터를 지우는 것이 좋습니다. VM 자체가 아닌 VM의 데이터를 관리해야합니다.
— BlackHatSamurai

내가 가진 문제는 이전 VM이 실제로 이전 LiveData를 제공하고 다른 구성 요소에 이전 데이터를 제공한다는 것입니다. 따라서 이전 VM이 계속 간섭하기 때문에 데이터를 지우지 않아도됩니다. 예 : 현재 ViewModel에서 목록을 지 웁니다. 그러나 화면에는 여전히 이전 목록이 표시됩니다. ViewModel을 디버깅하고 List의 길이를 확인하면 지워지기 때문에 0이라고 표시됩니다. 유일한 논리적 설명은 이전 데이터를 제공하는 다른 ViewModel입니다.
— user123456789

각 조각에 동일한 VM을 사용하고 있습니까? 아니면 각 조각마다 자체 VM이 있습니까?
— BlackHatSamurai

답변:


3

귀하의 의견에 따라 Fragment를 사용하고 있으며 해당 Fragment 안에는 뷰 파서가 있습니다. 따라서 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
감사. 이안 한니발 라케가 이미 말했듯이 조각 자체를 전달하는 것으로 충분합니다. 적절한 구성자가 있는지 확인하십시오. 따라서 두 가지 대답이 모두 맞습니다.
— user123456789
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.