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

百万日活游戏InApp Billing V3调用getSkuDetails触发ANR求助

解决InApp Billing V3调用getSkuDetails导致的ANR问题

我之前在维护一款千万级DAU的游戏时,刚好遇到过和你几乎一模一样的ANR问题!先帮你拆解下问题根源,再给你可行的解决办法。

问题根源:你以为在后台线程,实际还是跑在了主线程

从你贴的ANR堆栈能明显看出来——getSkuDetails的Binder跨进程调用最终是在主线程的Looper循环里执行的!你看堆栈里的Handler.dispatchMessage和ActivityThread.main,说明你所谓的“独立线程”其实没真正把billing调用放到后台,大概率是你的线程逻辑里误用了主线程的Handler,把getSkuDetails的执行任务又post回了主线程(比如那个GameActivity$$Lambda$2.run是通过主线程Handler分发的)。

跨进程调用Google Play服务本身就可能有延迟,一旦在主线程执行,很容易因为超过系统的ANR阈值(一般是5秒)触发无响应。

具体解决办法

1. 把getSkuDetails彻底放在后台线程执行

别用主线程Handler来跑billing接口调用,直接用后台线程池或者异步任务执行,只有更新UI的逻辑才回到主线程。给你个Java的实现示例:

// 初始化一个后台线程池,全局复用就行
private ExecutorService billingExecutor = Executors.newSingleThreadExecutor();

// 调用getSkuDetails的方法
private void loadSkuDetails() {
    billingExecutor.execute(() -> {
        if (mService == null) {
            // 先确保IInAppBillingService绑定成功
            return;
        }
        try {
            Bundle params = new Bundle();
            params.putStringArrayList("ITEM_ID_LIST", Arrays.asList("your_sku_id_here"));
            // 这里才是真正在后台执行getSkuDetails
            Bundle skuDetailsBundle = mService.getSkuDetails(3, getPackageName(), "inapp", params);
            
            // 拿到结果后,只把UI更新逻辑切回主线程
            runOnUiThread(() -> {
                ArrayList<String> responseList = skuDetailsBundle.getStringArrayList("DETAILS_LIST");
                // 解析价格、更新UI等操作
            });
        } catch (RemoteException e) {
            e.printStackTrace();
            // 异常处理也切回主线程提示用户
            runOnUiThread(() -> {
                Toast.makeText(this, "加载商品失败,请稍后重试", Toast.LENGTH_SHORT).show();
            });
        }
    });
}

2. 给后台调用加超时保护

跨进程调用可能因为网络差、Google Play服务异常卡住,给后台任务加个超时,避免线程一直挂着:

Future<?> task = billingExecutor.submit(() -> {
    // 执行getSkuDetails调用逻辑
});

try {
    // 设置5秒超时,根据你的业务调整
    task.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    task.cancel(true);
    runOnUiThread(() -> {
        Toast.makeText(this, "加载超时,请检查网络", Toast.LENGTH_SHORT).show();
    });
} catch (Exception e) {
    e.printStackTrace();
}

3. 检查Service绑定逻辑

确保你绑定IInAppBillingService是异步的,不要在主线程同步等待绑定结果。正确的绑定方式是用bindService,在ServiceConnection的onServiceConnected回调里拿到服务实例,再执行后续的billing操作。

4. 兼容旧版Google Play服务

部分老版本的Google Play服务可能存在getSkuDetails的性能问题,建议在启动时检查服务版本:

int playServiceStatus = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
if (playServiceStatus != ConnectionResult.SUCCESS) {
    // 提示用户更新Google Play服务
    GoogleApiAvailability.getInstance().getErrorDialog(this, playServiceStatus, 1001).show();
}

最后总结

你现在的核心问题就是getSkuDetails没真正在后台跑,只要把这个跨进程调用彻底放到后台线程,再加上超时和异常处理,ANR问题就能解决。我当初就是因为图省事,用了主线程Handler来执行billing调用,结果导致大量ANR,调整线程逻辑后就再也没出现过了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:09:13