美文网首页
不同的内联扩展函数来获取viewmodel

不同的内联扩展函数来获取viewmodel

作者: 长点点 | 来源:发表于2023-05-28 16:00 被阅读0次
    MavericksViewModel是一种用于MVI开发的类,它可以管理和更新MavericksState,以及提供一个状态流供其他类订阅。
    函数 异同 使用场景 优点 缺点
    fragmentViewModel 用于在Fragment中获取或创建一个新的MavericksViewModel实例,这个实例的生命周期和Fragment相同 每个Fragment都需要独立的ViewModel的情况。 可以避免ViewModel的数据混乱或泄露。 不能和其他Fragment共享数据和状态。
    parentFragmentViewModel 用于在Fragment中获取或创建一个和父Fragment共享的MavericksViewModel实例,这个实例的生命周期和父Fragment相同 子Fragment和父Fragment需要共享数据和状态的情况。 可以简化数据传递和更新。 需要遍历所有的父Fragment来寻找或创建ViewModel实例,可能会影响性能。
    targetFragmentViewModel 用于在Fragment中获取或创建一个和目标Fragment(通过setTargetFragment设置)共享的MavericksViewModel实例,这个实例的生命周期和目标Fragment相同 两个不相关的Fragment需要共享数据和状态的情况。 可以灵活地指定目标Fragment。 需要处理目标Fragment不存在或没有对应ViewModel的异常情况。
    existingViewModel 用于在Fragment中获取一个已经存在的MavericksViewModel实例,这个实例的生命周期和Activity相同 在流程中间的页面,不能作为流程的入口点。 可以保证获取到正确的ViewModel实例。 需要处理没有找到对应ViewModel的异常情况。
    viewModel 用于在Activity中获取或创建一个新的MavericksViewModel实例,这个实例的生命周期和Activity相同 任何Activity中使用ViewModel的情况。 可以方便地初始化和获取ViewModel实例。 可能会造成ViewModel的数据过大或不一致。

    fragmentViewModel函数

    有三个泛型类型参数:

    • T: Fragment的子类,也必须实现MavericksView接口。
    • VM: MavericksViewModel的子类,用于指定要获取的ViewModel的类型。
    • S: MavericksState的子类,用于指定ViewModel的状态类型。

    fragmentViewModel函数有两个可选参数:

    • viewModelClass: 用于指定ViewModel的类对象,默认为VM::class。
    • keyFactory: 用于生成ViewModel的唯一标识符,默认为viewModelClass.java.name。

    fragmentViewModel函数的返回值是一个MavericksDelegateProvider,它是一个接口,用于提供一个lazy delegate来获取或创建ViewModel。fragmentViewModel函数内部调用了viewModelDelegateProvider函数,传入了viewModelClass,keyFactory,existingViewModel = false(表示不使用已存在的ViewModel),以及一个lambda表达式,用于创建一个新的ViewModel实例。这个lambda表达式使用了MavericksViewModelProvider.get函数,传入了viewModelClass,stateClass,viewModelContext(包含了activity和args),key,以及initialStateFactory(用于初始化状态)。

    Fragment可以通过一个lazy delegate来获取或创建一个新的MavericksViewModel实例,并且可以指定ViewModel和State的类型以及keyFactory。

    inline fun <T, reified VM : MavericksViewModel<S>, reified S : MavericksState> T.fragmentViewModel(
        viewModelClass: KClass<VM> = VM::class,
        crossinline keyFactory: () -> String = { viewModelClass.java.name }
    ): MavericksDelegateProvider<T, VM> where T : Fragment, T : MavericksView =
        viewModelDelegateProvider(
            viewModelClass,
            keyFactory,
            existingViewModel = false
        ) { stateFactory ->
            MavericksViewModelProvider.get(
                viewModelClass = viewModelClass.java,
                stateClass = S::class.java,
                viewModelContext = FragmentViewModelContext(
                    activity = requireActivity(),
                    args = _fragmentArgsProvider(),
                    fragment = this
                ),
                key = keyFactory(),
                initialStateFactory = stateFactory
            )
        }
    
    inline fun <T, reified VM : MavericksViewModel<S>, reified S : MavericksState> T.parentFragmentViewModel(
        viewModelClass: KClass<VM> = VM::class,
        crossinline keyFactory: () -> String = { viewModelClass.java.name }
    ): MavericksDelegateProvider<T, VM> where T : Fragment, T : MavericksView =
        viewModelDelegateProvider(
            viewModelClass,
            keyFactory,
            existingViewModel = true 
            // 'existingViewModel'设置为true。虽然这个函数在两种情况下都能工作,
           //即已存在或新建的viewmodel,但是支持两种情况会比较困难,所以我们只测试常见的情况,
            //即“已存在”。我们不能确定这个fragment是否被设计为在非已存在的情况下使用(比如它可能需要参数)
            
        ) { stateFactory ->
            if (parentFragment == null) {
                // 使用ViewModelDoesNotExistException,这样模拟框架可以拦截并模拟这种情况下的viewmodel。
                throw ViewModelDoesNotExistException(
                    "There is no parent fragment for ${this::class.java.name} so view model ${viewModelClass.java.name} could not be found." // ${this::class.java.name}没有父fragment,所以找不到view model ${viewModelClass.java.name}。
                )
            }
            var parent: Fragment? = parentFragment
            val key = keyFactory()
            while (parent != null) {
                try {
                    return@viewModelDelegateProvider MavericksViewModelProvider.get(
                        viewModelClass = viewModelClass.java,
                        stateClass = S::class.java,
                        viewModelContext = FragmentViewModelContext(
                            activity = this.requireActivity(),
                            args = _fragmentArgsProvider(),
                            fragment = parent
                        ),
                        key = key,
                        forExistingViewModel = true 
                        // 对于已存在的viewmodel,设置为true。
                    )
                } catch (e: ViewModelDoesNotExistException) {
                    parent = parent.parentFragment 
                    // 如果在当前父fragment中找不到viewmodel,就继续向上遍历父fragment。
                }
            }
    
            // 没有找到viewmodel。在最顶层的父fragment中创建一个新的。
            var topParentFragment = parentFragment
            while (topParentFragment?.parentFragment != null) {
                topParentFragment = topParentFragment.parentFragment
            }
            val viewModelContext = FragmentViewModelContext(
                requireActivity(),
                _fragmentArgsProvider(),
                topParentFragment!!
            )
    
            MavericksViewModelProvider.get(
                viewModelClass = viewModelClass.java,
                stateClass = S::class.java,
                viewModelContext = viewModelContext,
                key = keyFactory(),
                initialStateFactory = stateFactory
            )
        }
    
    inline fun <T, reified VM : MavericksViewModel<S>, reified S : MavericksState> T.targetFragmentViewModel(
        viewModelClass: KClass<VM> = VM::class,
        crossinline keyFactory: () -> String = { viewModelClass.java.name }
    ): MavericksDelegateProvider<T, VM> where T : Fragment, T : MavericksView =
        viewModelDelegateProvider(
            viewModelClass,
            keyFactory,
            existingViewModel = true
        ) { stateFactory ->
    
            @Suppress("DEPRECATION")
            val targetFragment =
                requireNotNull(targetFragment) { "There is no target fragment for ${this::class.java.name}!" }
    
            MavericksViewModelProvider.get(
                viewModelClass = viewModelClass.java,
                stateClass = S::class.java,
                viewModelContext = FragmentViewModelContext(
                    activity = requireActivity(),
                    args = targetFragment._fragmentArgsProvider(),
                    fragment = targetFragment
                ),
                key = keyFactory(),
                initialStateFactory = stateFactory
            )
        }
    
    inline fun <T, reified VM : MavericksViewModel<S>, reified S : MavericksState> T.existingViewModel(
        viewModelClass: KClass<VM> = VM::class,
        crossinline keyFactory: () -> String = { viewModelClass.java.name }
    ): MavericksDelegateProvider<T, VM> where T : Fragment, T : MavericksView =
        viewModelDelegateProvider(
            viewModelClass,
            keyFactory,
            existingViewModel = true
        ) { stateFactory ->
    
            MavericksViewModelProvider.get(
                viewModelClass = viewModelClass.java,
                stateClass = S::class.java,
                viewModelContext = ActivityViewModelContext(
                    requireActivity(),
                    _fragmentArgsProvider()
                ),
                key = keyFactory(),
                initialStateFactory = stateFactory,
                forExistingViewModel = true
            )
        }
    
    inline fun <T, reified VM : MavericksViewModel<S>, reified S : MavericksState> T.activityViewModel(
        viewModelClass: KClass<VM> = VM::class,
        noinline keyFactory: () -> String = { viewModelClass.java.name }
    ): MavericksDelegateProvider<T, VM> where T : Fragment, T : MavericksView =
        viewModelDelegateProvider(
            viewModelClass,
            keyFactory,
            existingViewModel = false
        ) { stateFactory ->
    
            MavericksViewModelProvider.get(
                viewModelClass = viewModelClass.java,
                stateClass = S::class.java,
                viewModelContext = ActivityViewModelContext(
                    activity = requireActivity(),
                    args = _fragmentArgsProvider()
                ),
                key = keyFactory(),
                initialStateFactory = stateFactory
            )
        }
    
    inline fun <T, reified VM : MavericksViewModel<S>, reified S : MavericksState> T.viewModel(
        viewModelClass: KClass<VM> = VM::class,
        crossinline keyFactory: () -> String = { viewModelClass.java.name }
    ): Lazy<VM> where T : ComponentActivity = lifecycleAwareLazy(this) {
        MavericksViewModelProvider.get(
            viewModelClass = viewModelClass.java,
            stateClass = S::class.java,
            viewModelContext = ActivityViewModelContext(this, intent.extras?.get(Mavericks.KEY_ARG)),
            key = keyFactory()
        )
    }
    

    每个函数的代码示例,假设有一个OrderViewModel和一个OrderState用于管理订单的数据和状态。

    - fragmentViewModel: 在Fragment中使用这个函数,可以这样写:
    class OrderFragment: Fragment(), MavericksView {
    
      // 获取或创建一个新的OrderViewModel实例
      private val viewModel: OrderViewModel by fragmentViewModel()
    
      override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
      ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_order, container, false)
      }
    
      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    
        // 绑定视图和数据
        binding.viewModel = viewModel
        binding.lifecycleOwner = viewLifecycleOwner
    
        // 设置点击事件
        binding.buttonConfirm.setOnClickListener {
          viewModel.confirmOrder()
        }
      }
    
      override fun invalidate() {
        // 更新UI
        withState(viewModel) { state ->
          binding.textViewOrderStatus.text = state.orderStatus
          binding.textViewOrderPrice.text = state.orderPrice.toString()
        }
      }
    }
    
    - parentFragmentViewModel: 在子Fragment中使用这个函数,可以这样写:
    class OrderDetailFragment: Fragment(), MavericksView {
    
      // 获取或创建一个和父Fragment共享的OrderViewModel实例
      private val viewModel: OrderViewModel by parentFragmentViewModel()
    
      override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
      ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_order_detail, container, false)
      }
    
      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    
        // 绑定视图和数据
        binding.viewModel = viewModel
        binding.lifecycleOwner = viewLifecycleOwner
    
        // 设置点击事件
        binding.buttonEdit.setOnClickListener {
          viewModel.editOrder()
        }
      }
    
      override fun invalidate() {
        // 更新UI
        withState(viewModel) { state ->
          binding.textViewOrderDetail.text = state.orderDetail
          binding.textViewOrderNote.text = state.orderNote
        }
      }
    }
    
    - targetFragmentViewModel: 在Fragment中使用这个函数,可以这样写:
    class OrderSummaryFragment: Fragment(), MavericksView {
    
      // 获取或创建一个和目标Fragment(通过setTargetFragment设置)共享的OrderViewModel实例
      private val viewModel: OrderViewModel by targetFragmentViewModel()
    
      override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
      ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_order_summary, container, false)
      }
    
      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    
        // 绑定视图和数据
        binding.viewModel = viewModel
        binding.lifecycleOwner = viewLifecycleOwner
    
        // 设置点击事件
        binding.buttonPay.setOnClickListener {
          viewModel.payOrder()
          findNavController().navigate(R.id.action_orderSummaryFragment_to_paymentFragment)
        }
      }
    
      override fun invalidate() {
        // 更新UI
        withState(viewModel) { state ->
          binding.textViewOrderSummary.text = state.orderSummary
          binding.textViewTotalPrice.text = state.totalPrice.toString()
          binding.textViewDiscount.text = state.discount.toString()
          binding.textViewTax.text = state.tax.toString()
          binding.textViewFinalPrice.text = state.finalPrice.toString()
        }
      }
    }
    
    - existingViewModel: 在Fragment中使用这个函数,可以这样写:
    class PaymentFragment: Fragment(), MavericksView {
    
      // 获取一个已经存在的OrderViewModel实例,如果没有找到,会抛出异常
      private val viewModel: OrderViewModel by existingViewModel()
    
      override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
      ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_payment, container, false)
      }
    
      override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    
         // 绑定视图和数据
         binding.viewModel = viewModel
         binding.lifecycleOwner = viewLifecycleOwner
    
         // 设置点击事件
         binding.buttonSubmit.setOnClickListener {
           viewModel.submitPayment()
           findNavController().navigate(R.id.action_paymentFragment_to_thankYouFragment)
         }
       }
    
       override fun invalidate() {
         // 更新UI
         withState(viewModel) { state ->
           binding.textViewFinalPrice.text = state.finalPrice.toString()
           binding.editTextCardNumber.setText(state.cardNumber)
           binding.editTextCardName.setText(state.cardName)
           binding.editTextCardExpiry.setText(state.cardExpiry)
           binding.editTextCardCvv.setText(state.cardCvv)
         }
       }
    }
    
    - viewModel: 在Activity中使用这个函数,可以这样写:
    class OrderActivity : AppCompatActivity() {
    
       // 获取或创建一个新的OrderViewModel实例
       private val viewModel : OrderViewModel by viewModel()
    
       override fun onCreate(savedInstanceState : Bundle?) {
           super.onCreate(savedInstanceState)
    
           setContentView(R.layout.activity_order)
    
           // 设置标题栏文字为订单号码
           supportActionBar?.title = "Order #${viewModel.state.orderNumber}"
       }
    }
    

    相关文章

      网友评论

          本文标题:不同的内联扩展函数来获取viewmodel

          本文链接:https://www.haomeiwen.com/subject/geldedtx.html