You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Play Billing 4构建BillingClient时触发Too many receivers报错

问题根因分析
  • Google Play Billing 4.x版本的BillingClient在调用build()方法构造实例时,内部会自动注册用于接收支付状态变更的广播接收器,每新建一个BillingClient实例就会对应注册一个新的接收器
  • 你当前的代码没有限制BillingManager的实例创建次数,也没有补充BillingClient的销毁逻辑,如果业务侧每次需要调用支付能力时都新建BillingManager实例,就会导致广播接收器持续累积,达到系统单进程1000个广播接收器的上限后就会触发该崩溃
  • 仅在部分设备触发的原因是:只有使用时长较长、多次触发支付模块初始化的用户才会累积到1000的阈值,新用户、很少使用支付功能的用户不会触发
修复方案

1. 将BillingManager改为全局单例

全局只初始化一次BillingClient实例,避免重复构造

2. 补充资源销毁逻辑

在应用退出或者不需要使用支付能力时,主动调用BillingClient的endConnection()方法释放内部注册的广播接收器

3. 添加初始化防重逻辑

避免同一时间多次触发初始化操作

修改后参考代码
// 改成单例实现,可根据业务调整为懒汉式
class BillingManager private constructor(
    private val context: Context,
    private val firebase: FirebaseManager,
    private val storage: SharedPreferenceStorage
) {
    companion object {
        @Volatile
        private var INSTANCE: BillingManager? = null
        // 传入Application Context避免内存泄漏
        fun getInstance(
            context: Context,
            firebase: FirebaseManager,
            storage: SharedPreferenceStorage
        ): BillingManager {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: BillingManager(context.applicationContext, firebase, storage).also {
                    INSTANCE = it
                }
            }
        }
    }

    private var billingClient: BillingClient? = null
    val initBillingResponse = MutableLiveData<Boolean?>()
    // 标记是否正在初始化,避免重复触发
    private var isInitializing = false

    private val startConnectionListener = object : BillingClientStateListener {
        override fun onBillingSetupFinished(result: BillingResult) {
            isInitializing = false
            if (result.isResponseOk()) {
                getSKUs()
                checkSubscription()
                initBillingResponse.postValue(true)
            } else {
                initBillingResponse.postValue(false)
            }
        }

        override fun onBillingServiceDisconnected() {
            isInitializing = false
            initBillingResponse.postValue(false)
            // 可选:如果需要保持连接可以在这里加重试逻辑,注意限制重试次数避免死循环
        }
    }
  
    init {
        initBilling()
    }

    private fun initBilling() {
        // 已经初始化完成或者正在初始化直接返回
        if ((billingClient?.isReady == true) || isInitializing) {
            initBillingResponse.postValue(true)
            return
        }
        isInitializing = true
        initBillingResponse.postValue(null)

        try {
            billingClient = BillingClient.newBuilder(context)
                .enablePendingPurchases()
                .setListener { billingResult, purchases ->
                    if (billingResult.isResponseOk()) {
                        acknowledgePurchases(purchases)
                        checkSubscription()
                    }
                }
                .build()

            billingClient?.startConnection(startConnectionListener)
        } catch (e: Throwable) {
            isInitializing = false
            e.printStackTrace()
            FirebaseCrashlytics.getInstance().recordException(e)
            initBillingResponse.postValue(false)
        }
    }

    // 新增销毁方法,在应用退出时主动调用
    fun destroy() {
        runCatching {
            billingClient?.takeIf { it.isReady }?.endConnection()
        }
        billingClient = null
        INSTANCE = null
    }

    // Other functions
}

内容的提问来源于stack exchange,提问作者Peyman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 20:54:04