我有一个包含许多活动的应用程序。活动之一是显示购买选项。
在计费库(https://github.com/googlesamples/android-play-billing)的示例应用程序中,使用BillingClientLifecycle和BillingManager,它们都与单个活动相关联,因此在创建/销毁活动时会打开/关闭连接。
但是,在具有许多活动的应用程序中,针对不同的活动单独执行此操作似乎并不理想。我还想在应用启动时检查订阅是否有效。
我正在考虑在应用程序的Application子类中创建BillingClient。但是,如果这样做,我只会打开BillingClient连接而不关闭它(因为那里没有onDestroy方法)。有人做过此事并且遇到任何问题吗?另外,这是否违反最佳做法,还会导致网络/性能出现任何问题吗?
答案 0 :(得分:1)
看起来可以使用体系结构组件来完成。即在应用程序的OnCreate中,调用:
ProcessLifecycleOwner.get()。lifecycle.addObserver(billingClient)
然后将billingClient注入需要它的活动中。
答案 1 :(得分:1)
我通读了BillingClientImpl.java
中billing-1.2.2-sources.jar
的源代码,并且我相信将BillingClient
用作应用程序单例是安全的,即使这意味着从不调用BillingClient.endConnection()
BillingClientImpl.java
在其构造函数中不需要/使用Activity
;它使用Context
,而它所做的只是调用context.getApplicationContext()
来存储应用上下文。 launchBillingFlow
方法确实有一个Activity
参数,但是没有存储活动。它的唯一目的是调用具有计费意图的activity.startActivity(intent)
。
BillingClient.startConnection
调用context.registerReceiver
将其自己的BillingBroadcastReceiver
注册为BroadcastReceiver
,然后调用context.bindService
绑定服务连接。 (同样,这两个调用都是针对应用上下文mApplicationContext
执行的,而不是针对任何特定的Activity
执行的。)
只要在应用程序的生命周期内需要计费客户端,在registerReceiver
中调用bindService
和Application.onCreate()
且从不调用unregisterReceiver
是安全和可接受的或unbindService
。
如果registerReceiver
和/或bindService
调用使用Activity
上下文,这将是不安全的,因为ServiceConnection
在Activity
被使用时会泄漏。已销毁,但是当销毁该应用程序时,其过程将终止,并自动清除其所有服务连接。
答案 2 :(得分:1)
关于计费库的更新的2.x版本,引自TrivialDriveKotlin官方演示应用BillingRepository来源的报价:
请注意,已建立与[playStoreBillingClient]的连接 使用applicationContext。这意味着实例不是 [活动]特定。而且由于它也不昂贵,因此可以保留 在整个[应用程序]的整个生命周期内都是开放的。所以不管是 为每个[活动]或[片段]创建(重新),或为 应用程序的寿命是一个选择问题。
我想这也适用于第一个版本。
答案 3 :(得分:0)
“我建议不要创建一个 Singleton类,该类从中提供BillingClient
,并通过应用程序类进行初始化。”
为什么?因为这样做会在使用整个应用程序时泄漏内存或对象。
另一种方法是将此类制作为LifecycleObserver
,这样一来,尽管您将其绑定到Activity/Fragment
上,但仍然尊重它的生命周期,并相应地做事。
我已经创建了如下所示的类,并在我的一些项目中使用了(在其中,它运行良好)。
查看以下课程:
InAppBilling.kt
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/Fragment
中使用BillingClient
的地方:
private var mBillingClient: InAppBilling? = null
//.. And inside of onCreate() method, you'll just need to initialize it like below:
mBillingClient = InAppBilling(this@Activity.lifecycle, this)
现在,您可以使用此 billingClient对象从应用程序内客户端执行所需的操作。
您需要做的就是将您的特定方法添加到 InAppBilling类,并在所需的位置使用该方法。
从 this gist 中检出相同的班级。
答案 4 :(得分:0)
进行BaseActivity,并让所有其他活动扩展基本活动。在BaseActivity中创建结算实例。
无需执行应用程序类。与在应用程序中一样,退出应用程序时不会收到事件。另外,如果将应用程序置于后台,则应用程序实例仍然存在,因此连接将保持不必要的打开状态。
答案 5 :(得分:-1)
BillingClient需要当前活动,因为它需要当前窗口令牌才能向用户显示购买对话框。因此,每次活动更改 window令牌时也会发生更改,因此您无法使用singleton类进行此操作,因为在singleton类中,您正在泄漏活动参考,并且还提供了一个 window令牌在您的应用会话中无效。