ViewModel Scoping和Google Play计费库
#kotlin #android #mobile #tristan

目录

  1. Introduction
  2. Problem I am solving
  3. ViewModel Scopes
  4. Recreating the problem
  5. Fixing the problem

我在Google Playstore上的应用程序

github代码

简介

  • 本系列将是我面临的问题以及如何解决问题的非正式演示。本系列中的每个博客文章都将是独特的,并且与其他博客文章是独一无二的,因此请随时环顾四周。

ViewModels和Google的计费库的问题

It's strongly recommended that you have one active BillingClient connection open at one time to avoid multiple PurchasesUpdatedListener callbacks for a single event.

  • 大声读出来似乎是合乎逻辑的,没有什么可担心的。但是,这使我问这个问题,When is my code creating a BillingClient and how is it even possible create multiple of them?

  • 事实证明,我拥有Billingclient HERE,并将其创建实例委派给ViewModel HERE。因此,这意味着每次我创建某个ViewModel时,都会创建一个BillingClient,并且将创建publiceUpdateDlistener回调。然后,这将我们提出了When does our ViewModel get created?的问题。要回答这个问题,我们必须了解一些有关ViewModel范围的信息。

ViewModel Scopes

  • 每当创建一个ViewModel时,都会将其范围示为实现ViewModelStoreOwner接口的对象。这可以是一个活动,碎片,导航图或实现ViewModelStoreOwner接口的任何其他类。考虑到这一点很重要,因为ViewModel的生命周期直接与其范围相关。这意味着ViewModel保留在存储器中,直到它范围范围的ViewModelStoreOwner消失为止。这可能是由于以下原因而发生的:

1)当活动完成(用户解雇)
2)当碎片从碎片曼格脱离时
3)在导航期间,当它从后堆中删除时

范围API

  • 为了确定我们的视图模型,我们将重点关注这两个扩展功能:

1)viewModels():此扩展功能将把视图模型范围范围为最接近的ViewModelsStoreOwner。如果它在片段内使用(这是我使用的),则将范围范围范围内。如果在活动内部使用,则将范围为活动。

2)ActivityViewModels():通过使用此扩展功能,我们能够从片段的内部获得活动示波的ViewModel。因此,对于片段的oncreateview()方法,我们可以做到这一点:

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val billingViewModel: BillingViewModel by activityViewModels()

  • 这将使我们的billingViewModel能够像活动一样持续。当您在多个片段中使用val billingViewModel: BillingViewModel by activityViewModels()时,这会变得非常有趣。您认为会发生什么?另一个活动范围的视图模型是否得到创建,或者Android系统恢复同一实例????正确的! Android系统恢复同一实例。

多个billingclient连接问题

  • 现在,我们俩都知道一些范围,我们可以谈论multiple BillingClient connection problem,以及为什么将范围范围范围的范围和导航组件组合起来会导致它。在我的应用中,我使用Navigation Component,该Navigation Component处理所有片段实例化本身,这真的很棒。当我们将ViewModel示意为片段时,然后我们的用户围绕应用程序导航时,就会出现multiple BillingClient connection problem,而不会从后堆栈中弹出片段。高水平的有问题的导航看起来像这样:

problematic navigation

  • 箭头每次从房屋片段导航到订阅片段时都会演示。

  • 现在,由于视图模型范围为订阅片段。每次用户导航到该片段时,导航组件都会创建订阅片段的新实例,该实例创建了BillingViewModel的新实例,该实例创建了一个新的BillingClient实例,创建一个publicesUpdateDlistener回调,并且每个实例都在存储这些实例在后堆上。这会导致单个事件有多个PurchasesUpdatedListener回调(真正的麻烦)。

解决多个Billingclient连接问题

  • 解决此问题的解决方案非常容易,我们只需要使用activityViewModels()扩展功能将ViewModel的范围从片段更改为活动。因此,在片段的onCreateView()中,我们可以做到这一点:
override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val billingViewModel: BillingViewModel by activityViewModels()

  • 现在可以将billingViewModel传递给我们的组合:
binding.composeView.apply{
            setContent {

                // composable function
                MainView(
                    billingViewModel = billingViewModel
                )
            }

        }

  • 正如我之前提到的,activityViewModels()非常有趣,因为它只会创建一个billingViewModel的实例,然后如果我们从任何其他片段中调用val billingViewModel: BillingViewModel by activityViewModels() 系统将重复使用同一实例。因此,随着片段通过导航组件自动创建和破坏,只有在用户完全驳回活动并被销毁的活动后,billingViewModel才会被销毁。

结论

  • 感谢您抽出宝贵的时间阅读我的博客文章。如果您有任何疑问或疑虑,请在下面发表评论或在Twitter上与我联系。