整个应用程序中BillingClient的一个实例

问题描述 投票:2回答:5

我有一个有很多活动的应用程序。其中一项活动是显示购买选项。

在计费库(https://github.com/googlesamples/android-play-billing)的示例应用程序中,使用BillingClientLifecycle和BillingManager,它们都与单个活动相关联,因此在创建/销毁活动时打开/关闭连接。

但是,在具有许多活动的应用程序中,为不同的活动单独执行此操作似乎并不理想。我还想检查应用程序启动订阅是否有效。

我正在考虑在应用程序的Application子类中创建BillingClient。但是,如果我这样做,我只会打开BillingClient连接而不关闭它(因为那里没有onDestroy方法)。有没有人之前做过这件事并遇到任何问题?这也违反了最佳做法,是否会导致网络/性能出现问题?

android in-app-purchase in-app-billing
5个回答
1
投票

看起来这可以通过架构组件来完成。即在你的应用程序的OnCreate中,调用:

ProcessLifecycleOwner.get()。lifecycle.addObserver(billingClient)

然后将billingClient注入需要它的活动中。


1
投票

我读了BillingClientImpl.javabilling-1.2.2-sources.jar的来源,我相信使用BillingClient作为应用程序单例是安全的,即使这意味着从不调用BillingClient.endConnection()

BillingClientImpl.java在构造函数中不需要/使用Activity;它使用Context,它所做的只是调用context.getApplicationContext()来存储应用程序上下文。 launchBillingFlow方法确实有一个Activity参数,但是没有存储活动;它唯一的目的是使用结算意图调用activity.startActivity(intent)

BillingClient.startConnectioncontext.registerReceiver将自己的BillingBroadcastReceiver注册为BroadcastReceiver,然后调用context.bindService绑定服务连接。 (同样,这两个调用都是针对应用程序上下文mApplicationContext执行的,而不是针对任何特定的Activity执行。)

只要在应用程序的生命周期内需要结算客户端,在registerReceiver中调用bindServiceApplication.onCreate()并且永远不会调用unregisterReceiverunbindService是安全且可接受的。

如果registerReceiver和/或bindService调用使用Activity上下文,这将是不安全的,因为当ServiceConnection被销毁时Activity会泄漏,但是当应用程序被销毁时,它的进程终止,并且它的所有服务连接都被自动清理。


0
投票

“我建议不要创建一个从它提供BillingClient并通过应用程序类初始化的Singleton类。”

为什么?因为,以这种方式,你有可能在使用整个应用程序时泄漏内存或对象。


替代方法是使这样的类成为LifecycleObserver,这样一旦你将它绑定到你的Activity/Fragment虽然尊重它的生命周期并做相应的事情。

我已经创建了如下所示的类,并在我的一些项目中使用(其中,它的工作非常好)。

看看下面的课程:

Inppbillingkkt

class InAppBilling(val lifecycle: Lifecycle, purchasesUpdatedListener: PurchasesUpdatedListener) :
    LifecycleObserver,
    PurchasesUpdatedListener by purchasesUpdatedListener,
    BillingClientStateListener {

    companion object {
        const val TAG = "InAppBilling"
    }

    init {
        lifecycle.addObserver(this)
    }

    private var mBillingClient: BillingClient? = null

    private fun initClient(): BillingClient {
        return BillingClient
                .newBuilder(context) // You can provide application context here.
                .setListener(this)
                .build()
    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_CREATE)
    fun connectionToBillingServer() {
        mBillingClient = initClient()
        mBillingClient?.startConnection(this)
    }

    @OnLifecycleEvent(value = Lifecycle.Event.ON_DESTROY)
    fun disconnectFromBillingServer() {
        mBillingClient?.endConnection()
        lifecycle.removeObserver(this)
    }

    override fun onBillingServiceDisconnected() {
        if (lifecycle.currentState == Lifecycle.State.CREATED) {
            mBillingClient?.startConnection(this)
        }
    }

    override fun onBillingSetupFinished(responseCode: Int) {
        // Left out because "Unused"
    }
}

以及如何消费它:

在你想要使用Activity/FragmentBillingClient里面:

private var mBillingClient: InAppBilling? = null

//.. And inside of onCreate() method, you'll just need to initialize it like below:
    mBillingClient = InAppBilling([email protected], this)

现在,您可以使用此billingClient对象从In-App客户端执行您想要的内容。

您需要做的就是将您的特定方法添加到InAppBilling类中,并将该方法用于您想要的位置。

查看this gist的同一课程。


0
投票

创建BaseActivity并让所有其他活动扩展基本活动。在BaseActivity中创建计费实例。

不需要做应用程序类。与在应用程序中一样,当退出应用程序时,您不会收到任何事件。另外,如果你把app放在后台,应用程序实例仍然存在,因此连接将不必要地保持打开。


-1
投票

BillingClient需要当前活动,因为它需要当前窗口令牌来向用户显示购买对话框。因此,每次活动更改窗口令牌也会更改,因此您无法使用单例类执行此操作,因为在单例类中,您正在泄漏活动引用并且还提供单个窗口令牌,该令牌在您的应用程序会话中无效。

© www.soinside.com 2019 - 2024. All rights reserved.