显示来自 BillingClient 的产品数据

问题描述 投票:0回答:1

我创建了以下 BillingManager 类来处理我的 Android 应用程序的 Google Play 计费库:

public class BillingManager {

    private List<ProductDetails> productDetailsList;

    private PurchasesUpdatedListener purchasesUpdatedListener = (billingResult, purchases) -> {
        // To be implemented in a later section.
    };

    private BillingClient billingClient = BillingClient.newBuilder(MyApplication.getAppContext())
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
            .build();

    public void establishConnection() {
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    Log.i("BillingManager", "Connected to Google Play.");
                    getProductDetails();
                }
            }
            @Override
            public void onBillingServiceDisconnected() {
                Log.i("BillingManager", "Disconnected from Google Play.");
                establishConnection();
            }
        });
    }

    private void getProductDetails() {
        QueryProductDetailsParams queryProductDetailsParams =
                QueryProductDetailsParams.newBuilder()
                        .setProductList(List.of(
                                QueryProductDetailsParams.Product.newBuilder()
                                        .setProductId("full_version")
                                        .setProductType(BillingClient.ProductType.INAPP)
                                        .build()))
                        .build();

        billingClient.queryProductDetailsAsync(
                queryProductDetailsParams,
                (billingResult, productDetailsList) -> {
                    this.productDetailsList = productDetailsList;
                }
        );

    }

    public List<ProductDetails> getProductDetailsList() {
        return productDetailsList;
    }

    public void launchPurchaseFlow(Activity activity, ProductDetails productDetails) {
        List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
                List.of(
                        BillingFlowParams.ProductDetailsParams.newBuilder()
                                // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
                                .setProductDetails(productDetails)
                                .build()
                );

        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                .setProductDetailsParamsList(productDetailsParamsList)
                .build();

    // Launch the billing flow
        BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
    }
}

这是我希望如何在我的 FragmentDialog 类之一中使用它的示例:

BillingManager billingManager = new BillingManager();
    billingManager.establishConnection();

    MaterialButton button = view.findViewById(R.id.button);

// This causes an outOfBounds exception
button.setText(billingManager.getProductDetailsList().get(0).getOneTimePurchaseOfferDetails().getFormattedPrice());

    button.setOnClickListener(v -> {
        billingManager.launchPurchaseFlow(getActivity(), billingManager.getProductDetailsList().get(0));
    });

}

问题:

我在尝试使用从 Google Play 结算库检索到的产品价格设置按钮文本时遇到 IndexOutOfBoundsException。导致问题的行是:

button.setText(billingManager.getProductDetailsList().get(0).getOneTimePurchaseOfferDetails().getFormattedPrice());

问题源于我的 BillingManager 类中的异步 setConnection 和 getProductDetails 方法。当片段启动并尝试访问产品详细信息以设置按钮文本时,这些操作尚未完成,导致列表为空或未初始化。

如何解决此问题并确保仅在建立与 Google Play Billing 的连接并且成功检索产品详细信息后才设置按钮的文本?

java android asynchronous android-billing play-billing-library
1个回答
0
投票

您可以创建一个界面

BillingStatusListener

interface BillingStatusListener {
   void onProductListFetched(List<YourType> productList);
   void onBillingSetupFinishedSuccessfully();
}

让你的

FragmentDialog
实现这个接口

class FragmentDialog implements BillingStatusListener {

   @Override
   void onProductListFetched(List<YourType> productList) {
      // Setup your button text here
      // You are sure to have data here, and no Null Pointer exceptions

   }
}

最后,让你的

BillingManager
接受上面接口的实现并根据需要使用它

public class BillingManager {

    private List<ProductDetails> productDetailsList;

    private PurchasesUpdatedListener purchasesUpdatedListener = (billingResult, purchases) -> {
        // To be implemented in a later section.
    };

   private BillingStatusListener billingStatusListener; // Initialise this somewhere with the FragmentDialog class as the implementation

    private BillingClient billingClient = BillingClient.newBuilder(MyApplication.getAppContext())
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
            .build();

    public void establishConnection() {
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    Log.i("BillingManager", "Connected to Google Play.");
                    getProductDetails();
                }
            }
            @Override
            public void onBillingServiceDisconnected() {
                Log.i("BillingManager", "Disconnected from Google Play.");
                establishConnection();
            }
        });
    }

    private void getProductDetails() {
        QueryProductDetailsParams queryProductDetailsParams =
                QueryProductDetailsParams.newBuilder()
                        .setProductList(List.of(
                                QueryProductDetailsParams.Product.newBuilder()
                                        .setProductId("full_version")
                                        .setProductType(BillingClient.ProductType.INAPP)
                                        .build()))
                        .build();

        billingClient.queryProductDetailsAsync(
                queryProductDetailsParams,
                (billingResult, productDetailsList) -> {
                    this.productDetailsList = productDetailsList;
                    // you will surely have data here
                    // so let's notify the interface
                    billingStatusListener.onProductListFetched(productDetailList);
                }
        );

    }

    public List<ProductDetails> getProductDetailsList() {
        return productDetailsList;
    }

    public void launchPurchaseFlow(Activity activity, ProductDetails productDetails) {
        List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
                List.of(
                        BillingFlowParams.ProductDetailsParams.newBuilder()
                                // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
                                .setProductDetails(productDetails)
                                .build()
                );

        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                .setProductDetailsParamsList(productDetailsParamsList)
                .build();

    // Launch the billing flow
        BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.