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

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

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值