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

IInAppBillingService始终为空,安卓内购查询空指针问题求助

解决应用内购买查询商品时的空指针异常问题

看起来你遇到的空指针异常,大概率是因为IInAppBillingService还没成功绑定就被调用了——毕竟内购服务的绑定是异步的,直接在Activity初始化阶段去调用查询,肯定会踩空。另外你用Handler排查等待问题没效果,可能是没搞对时机,反而打乱了服务绑定的流程。

我给你整理了一套靠谱的修正方案,一步步来:

1. 先确保服务绑定的正确流程

内购服务的绑定必须异步等待回调,不能急着调用方法。你需要在onCreate里发起绑定,然后在onServiceConnected回调里拿到服务实例后,再执行商品查询。

修正后的ServiceConnection和绑定逻辑:

public class AdOnsActivity extends AppCompatActivity {
    private IInAppBillingService mService;
    private ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 服务绑定成功,初始化mService
            mService = IInAppBillingService.Stub.asInterface(service);
            // 这里才是查询商品的正确时机!
            queryAvailableProducts();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ad_ons);

        // 发起内购服务绑定
        Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
        serviceIntent.setPackage("com.android.vending");
        bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
    }

    // 记得在销毁时解绑服务,避免内存泄漏
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mService != null) {
            unbindService(mServiceConn);
        }
    }
}

2. 正确实现商品查询逻辑

查询商品的方法必须在子线程执行(直接在主线程调用会触发ANR),拿到结果后再切回主线程更新UI。之前用Handler的思路没错,但要放在正确的地方:

private void queryAvailableProducts() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                // 替换成你自己的商品SKU列表
                ArrayList<String> skuList = new ArrayList<>();
                skuList.add("premium_feature");
                skuList.add("remove_ads");

                Bundle queryParams = new Bundle();
                queryParams.putStringArrayList("ITEM_ID_LIST", skuList);

                // 调用内购服务查询商品详情
                Bundle skuDetails = mService.getSkuDetails(3, getPackageName(), "inapp", queryParams);

                int responseCode = skuDetails.getInt("RESPONSE_CODE");
                if (responseCode == 0) {
                    ArrayList<String> detailList = skuDetails.getStringArrayList("DETAILS_LIST");
                    // 切回主线程更新UI
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // 解析商品详情,比如价格、名称等
                            for (String detail : detailList) {
                                JSONObject skuObj = new JSONObject(detail);
                                String sku = skuObj.getString("productId");
                                String price = skuObj.getString("price");
                                // 这里可以把商品信息展示到UI上
                            }
                        }
                    });
                } else {
                    // 处理查询失败的情况,比如提示用户检查网络
                    runOnUiThread(() -> Toast.makeText(AdOnsActivity.this, "查询商品失败", Toast.LENGTH_SHORT).show());
                }
            } catch (RemoteException | JSONException e) {
                e.printStackTrace();
                runOnUiThread(() -> Toast.makeText(AdOnsActivity.this, "查询出错", Toast.LENGTH_SHORT).show());
            }
        }
    }).start();
}

3. 别忘了检查基础配置

  • 确保AndroidManifest.xml里添加了内购权限:
<uses-permission android:name="com.android.vending.BILLING" />
  • 确认Google Play控制台里的应用内商品已经激活,且SKU和代码里的完全一致,包名也和你的应用匹配。
  • 测试时要用签名后的APK,或者用Android Studio的App Signing功能,否则可能无法连接到内购服务。

之前你用Handler排查等待问题没效果,应该是提前在绑定完成前就调用了mService的方法,导致空指针。现在按照这个流程,等服务绑定成功后再查询,就能避免空指针的问题啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:53:03