安卓内购调用querySkuDetailsAsync后SkuDetailsResponseListener仅部分代码执行
问题根因与修复方案
核心原因
出现该问题90%以上的概率是线程非法操作触发未捕获异常,导致回调流程被强制中断,Google Play Billing库的querySkuDetailsAsync回调默认运行在后台子线程,安卓系统禁止在子线程执行UI更新操作,不同系统版本对子线程UI操作的检查严格度不同:前两行给textProduct赋值的操作刚好未触发线程校验,后续赋值操作触发CalledFromWrongThreadException后直接终止了回调逻辑,没有捕获异常的情况下不会打印相关报错。
其余可能的触发原因:
- 控件未完成初始化或id匹配错误,
textDesc/btnPrice为null,调用赋值逻辑时触发空指针异常 - 返回的
SkuDetails对象中description/price字段为空,触发空值赋值异常 - 商品列表为空时直接取下标
list[0]触发数组越界异常
修复代码
fun getProductDetails() { val productIds = mutableListOf<String>() productIds.add("product1") val getProductDetailQuery: SkuDetailsParams = SkuDetailsParams .newBuilder() .setSkusList(productIds) .setType(BillingClient.SkuType.INAPP) .build() billingClient.querySkuDetailsAsync( getProductDetailQuery ) { billingResult, list -> if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && list?.isNotEmpty() == true) { val itemInfo: SkuDetails = list[0] // 切换到主线程执行所有UI相关操作 runOnUiThread { try { textProduct.text = itemInfo.title textDesc.text = itemInfo.description btnPrice.text = itemInfo.price btnPrice.setOnClickListener { billingClient.launchBillingFlow( this@BillingMainActivity, BillingFlowParams.newBuilder() .setSkuDetails(itemInfo) .build() ) } } catch (e: Exception) { // 捕获异常打印定位问题 logBilling("回调执行异常: ${e.message}") e.printStackTrace() } } } else { val error = BillingUtils.getBillingResponses(billingResult.responseCode) logBilling("getProductDetails error:$error") } } }
额外排查项
- 确认调用
getProductDetails()的时机晚于控件初始化逻辑,所有涉及的控件id与布局文件中定义一致 - 本地调试时可先打印
itemInfo.description、itemInfo.price的取值,确认内购商品配置正常无空字段
内容的提问来源于stack exchange,提问作者Ahmet B.
相关产品推荐
相关产品推荐

