Google InApp Billing - Binding title of skuDetailsList obtained from onSkuDetailsResponse to List View Control

Viewed 200

I am new to the implementation of Google's Billing library and using this system to make subscriptions inside my app. I am trying to get the title of skuDetailsList which is obtained from onSkuDetailsResponse and adding to the ArrayList dataSource. I am setting the ArraryList as datasource to the adapter . The issue is the ListView is getting displayed empty every time even though there are items available in the ArrayList DataSource.

I tried adding dummy values to the datasource and found that they are getting displayed in the list view control. So, i have I debugged the code and found that the view is getting returned first and then the items are getting added to the ArrayList Datasource as onSkuDetailsResponse is getting called asynchronously.

Following is the entire code used for establishing connection, getting the SKU Details , binding it array list and setting the adapter to the ListView Control in "OnCreateView"

Code for Establishing connection

private void startBillingServiceConnection(){
        //Initialize a billing client
        billingClient = BillingClient.newBuilder(this.getActivity())
                .setListener(this)
                .enablePendingPurchases()
                .build();
        //Establish a connection to Google Play
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() ==  BillingClient.BillingResponseCode.OK) {

                    // The BillingClient is ready. You can query purchases here....
                    querySkuDetails();                        
                }
            }
            @Override
            public void onBillingServiceDisconnected() {
                // Try to restart the connection on the next request to
                // Google Play by calling the startConnection() method.
            }
        });
    }

Code for querySkDetails

public void querySkuDetails() {
        Log.i(TAG, "querySkuDetails");

        SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
        params.setSkusList(LIST_OF_SKUS).setType(BillingClient.SkuType.SUBS);
        billingClient.querySkuDetailsAsync(params.build(),
                new SkuDetailsResponseListener() {
                    @Override
                    public void onSkuDetailsResponse(BillingResult billingResult,
                                                     List<SkuDetails> skuDetailsList) {
                        if (billingResult == null) {
                            return;
                        }
                        int responseCode = billingResult.getResponseCode();
                        String debugMessage = billingResult.getDebugMessage();
                        switch (responseCode) {
                            case BillingClient.BillingResponseCode.OK:
                                if (skuDetailsList != null && skuDetailsList.size() > 0) {
                                    subscribeItemDisplay.clear();
                                    for (SkuDetails p : skuDetailsList) {
                                        subscribeItemDisplay.add("Product Name - "+p.getOriginalPrice()+": "+p.getSubscriptionPeriod()+": "+p.getFreeTrialPeriod());
                                    }
                                }
                            
                            default:                                    
                                break;
                        }
                    }
                });
    }

Code in "OnCreateView"

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainHandler = new Handler();

        // Inflate layout
        View view = inflater.inflate(R.layout.subscribe_fragment, container, false);            
        subscriptionsListView = view.findViewById(R.id.subscriptionsView);            
        loadInAppProductIDS();            
        return view;
    }

Code for loadInAppProductIDS

public void loadInAppProductIDS() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                LIST_OF_SKUS= Collections.unmodifiableList(myProductIDs);
                startBillingServiceConnection();
                mainHandler.post(new Runnable() {
                    public void run() {
                        arrayAdapter = new ArrayAdapter<String>(getActivity(), R.layout.subscription_items_list, subscribeItemDisplay);
                        subscriptionsListView.setAdapter(arrayAdapter);
                    }
                });
            }
        }).start();
    }

Can you please suggest on how to add items to datasource, bind to the list view and then return the view?

3 Answers

The problem is you are setting adapter in beginning before list are loaded from onSkuDetailsResponse, You should just set adapter after you receive data. So your code should be like this:

View view = inflater.inflate(R.layout.subscribe_fragment, container, false);
---- Code here for establishing the connection to Google Play and querying skuDetails in the onBillingSetupFinished method ----
subscriptionsListView = view.findViewById(R.id.subscriptionsView);

return view;

and your onSkuDetailResponse should be like this:

public void onSkuDetailsResponse(BillingResult billingResult,
                                 List<SkuDetails> skuDetailsList) {
    if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
        if (skuDetailsList != null && skuDetailsList.size() > 0) {
            subscribeItemDisplay.clear();
            for(SkuDetails p:skuDetailsList){
                subscribeItemDisplay.add(p.getTitle());
            }
            arrayAdapter = new ArrayAdapter<String>(this.getActivity(),
                    R.layout.subscribtion_item_list, subscribeItemDisplay);
            subscriptionsListView.setAdapter(arrayAdapter);
        }
    }
}

In your ListView adapter create this method which add data to the listView.

public void add(String title) {
    titleLists.add(title)
    notifyItemInserted(titleLists.size - 1)
}

in your activity class call add() function.

if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                        if (skuDetailsList != null && skuDetailsList.size() > 0) 
                        {
                            subscribeItemDisplay.clear();
                            for(SkuDetails p:skuDetailsList){
                                subscribeItemDisplay.add(p.getTitle());
                                arrayAdapter.add(p.getTitle());
                            }
                        }
                    }

You can notify adapter after list filled.

public void onSkuDetailsResponse(BillingResult billingResult,
                                                     List<SkuDetails> skuDetailsList) {
                        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                            if (skuDetailsList != null && skuDetailsList.size() > 0) {
                                subscribeItemDisplay.clear();
                                for(SkuDetails p:skuDetailsList){
                                    subscribeItemDisplay.add(p.getTitle());
                                }
                                notifyDataSetChanged();
                            }
                        }
                    }
Related