【问题标题】:ViewModelProvider.Factory always return one viewmodelViewModelProvider.Factory 总是返回一个视图模型
【发布时间】:2021-06-17 14:17:33
【问题描述】:

我有一个TabLayout,包含三个Fragment(由同一实例创建)SectionsPagerAdapter。在片段内部,我尝试使用ViewModelProvider.Factory 创建独立的视图模型,但是,我发现所有片段总是与相同的数据一起更新内容。

我已经调试过,发现它总是返回相同的视图模型,即使 有区别BillType,和 奇怪的是,当进入活动时, Factory.create 只被调用一次。

// Log
D/BillType: OUTCOME
D/Factory crate BillType: OUTCOME
D/ViewModel Init BillType: OUTCOME
D/viewModel Bill:BillType: OUTCOME
D/BillType: INCOME
D/viewModel Bill:BillType: OUTCOME
D/BillType: TRANSFER
D/viewModel Bill:BillType: OUTCOME

我不知道哪里错了,之前的代码运行正常。

class BillViewModel(billType: BillType): ViewModel() {
    val bill: MutableLiveData<Bill> = MutableLiveData()

    init {
        Log.d("ViewModel Init BillType", billType.toString())
        bill.value = Bill.QBill().apply {
            type = billType
        }
    }

    class NewBillViewModelFactory(val billType: BillType): ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            Log.d("Factory crate BillType", billType.toString())
            return modelClass.getConstructor(BillType::class.java)
                .newInstance(billType)
        }
    }
}
enum class BillType(val type: Int) {
    OUTCOME(0),
    INCOME(1),
    TRANSFER(2);
}
class NewBillFragment: BaseFragment() {
    ...
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        billType = BillType.values()[arguments?.getInt(BILLTYPE, 0) ?: 0]
        Log.d("BillType", billType.toString())
        viewModel = ViewModelProvider(requireActivity(), NewBillViewModel.NewBillViewModelFactory(billType))[NewBillViewModel::class.java]
        Log.d("viewModel Bill:BillType", viewModel.bill.value?.type.toString())
        _binding = FragmentBillNewBinding.inflate(layoutInflater, container, false)
        with(binding) {
            data = viewModel
            lifecycleOwner = activity
        ... ui ...
        return binding.root
    }

    companion object {
        private const val BILLTYPE = "billtype"

        @JvmStatic
        fun newInstance(billType: Int): NewBillFragment {
            return NewBillFragment().apply {
                arguments = Bundle().apply {
                    putInt(BILLTYPE, billType)
                }
            }
        }
    }
}
class SectionsPagerAdapter(private val context: Context, fm: FragmentManager)
    : FragmentPagerAdapter(fm) {

    override fun getItem(position: Int): Fragment = BillFragment.newInstance(position)

    override fun getPageTitle(position: Int): CharSequence = context.resources.getString(TAB_TITLES[position])

    override fun getCount(): Int = 3
}

【问题讨论】:

    标签: android android-fragments mvvm viewmodel android-viewmodel


    【解决方案1】:

    因为您正在使用 requireActivity() 创建共享 ViewModel 。所以它会参考Activity而不是Fragment返回ViewModel

    如果你想保持ViewModel Fragment 作用域那么你应该将Fragment 传递为ViewModelStoreOwner

            viewModel = ViewModelProvider(this, NewBillViewModel.NewBillViewModelFactory(billType))[NewBillViewModel::class.java]
    

    【讨论】:

    • 太愚蠢了!我曾尝试创建三个新的 ViewModel 类来解决这个问题,它也可以解决它但很愚蠢。一直用requireActivity()来获取ViewModel,被那么多文章误导了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-20
    • 2014-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多