aAaDesigner
aAaDesigner

Reputation: 21

RecyclerView billingClient: No adapter attached; skipping layout, Sometimes it works, sometimes it doesn't

first time I use billingclient, but I have a problem, by the console it gives me the error: RecyclerView billingClient: No adapter attached; skipping layout and sometimes it loads the RecyclerView and sometimes it doesn't, that is, I enter the activity and sometimes it loads it and many times it doesn't

I leave the code for an expert to guide me and I can help myself to see where I have a fault

suscripcion.java

private BillingClient billingClient;
    private AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener;
    private RecyclerView recyclerView_sub;
    private DocumentReference documentReference;
    private FirebaseFirestore mFirestore;
    private FirebaseUser user;
    private FirebaseAuth fAuth;
    private String userID;


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

        mFirestore = FirebaseFirestore.getInstance();
        fAuth = FirebaseAuth.getInstance();
        user = fAuth.getCurrentUser();

        if (user !=null)
        {
            userID = fAuth.getCurrentUser().getUid();
        }

        documentReference = mFirestore.collection("users").document(userID);

        setupSubClient();
        iniciador();

        txtclose = findViewById(R.id.txtclosesub);
        txtclose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
                startActivity(new Intent(suscripcion.this, MainActivity.class));
            }
        });
    }

    private void iniciador() {

        statuspremium = findViewById(R.id.statuspremium);
        rangopremium = findViewById(R.id.rangopremium);
        recyclerView_sub = findViewById(R.id.recyclerview_sub);
        recyclerView_sub.setHasFixedSize(true);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView_sub.setLayoutManager(layoutManager);
        recyclerView_sub.addItemDecoration(new DividerItemDecoration(this, layoutManager.getOrientation()));

    }

    private void loadAllSubPackage() {

        if (billingClient.isReady())
        {
            SkuDetailsParams params = SkuDetailsParams.newBuilder()
                    .setSkusList(Arrays.asList("vf_sub_unmes", "vf_sub_tresmes"))
                    .setType(BillingClient.SkuType.SUBS)
                    .build();
            billingClient.querySkuDetailsAsync(params, new SkuDetailsResponseListener() {
                @Override
                public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {

                    if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)

                    {

                        MySubAdapter adapter = new MySubAdapter(suscripcion.this, list, billingClient);
                        recyclerView_sub.setAdapter(adapter);
                        

                    }else
                    {
                        Log.d("ERROR", "onSkuDetailsResponse: " + billingResult.getResponseCode());

                    }
                }
            });
        }else
        {
            Log.d("ERROR", "loadAllSubPackage: Billing cliente not ready" );

        }

    }

    private void setupSubClient() {
        acknowledgePurchaseResponseListener = new AcknowledgePurchaseResponseListener() {
            @Override
            public void onAcknowledgePurchaseResponse(@NonNull BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
                {
                    Log.d("ERROR", "onAcknowledgePurchaseResponse: " +
                            billingResult.getResponseCode());
//                    rangopremium.setVisibility(View.VISIBLE);
//                    tiemposub.setVisibility(View.VISIBLE);
                }
            }
        };

        billingClient = BillingClientSetup.getInstance(this, this);
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingServiceDisconnected() {

                Log.d("ERROR", "onBillingServiceDisconnected: " );


            }

            @Override
            public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
                {
                    Log.d("ERROR", "onBillingSetupFinished: " +
                            billingResult.getResponseCode());

//                    //Query
//                    List<Purchase> purchases = billingClient.queryPurchases(BillingClient.SkuType.SUBS)
//                            .getPurchasesList();

                    billingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS, new PurchasesResponseListener() {
                        @Override
                        public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> list) {

                            if (list.size() > 0)
                            {

                                for (Purchase purchase:list)

                                    handleSubAlreadyPurchase(purchase);

                                Log.d("ERROR", "onBillingSetupFinished: " +
                                        billingResult.getResponseCode());

                            }else
                            {

                                loadAllSubPackage();
                                documentReference.update("premium", "no");
                                documentReference.update("status", "user");
                                statuspremium.setVisibility(View.VISIBLE);

                                Log.d("ERROR", "onBillingSetupFinished: " +
                                        billingResult.getResponseCode());
//                            rangopremium.setVisibility(View.GONE);
//                            tiemposub.setVisibility(View.GONE);
//                            statuspremium.setVisibility(View.VISIBLE);
//                            recyclerView_sub.setVisibility(View.VISIBLE);

                            }

                        }
                    });






                }
                else
                    {
                        Log.d("ERROR", "onBillingSetupFinished: " +
                                billingResult.getResponseCode());

                    }
            }
        });
    }


    private void handleSubAlreadyPurchase(Purchase purchases) {

       if (purchases.getPurchaseState() == Purchase.PurchaseState.PURCHASED)
       {
           rangopremium.setVisibility(View.VISIBLE);
           Log.d("ERROR", "handleSubAlreadyPurchase: ");
           if (!purchases.isAcknowledged())
           {
               Log.d("ERROR", "handleSubAlreadyPurchase: ");
               AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                       .setPurchaseToken(purchases.getPurchaseToken())
                       .build();
               billingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
           }else
               {
                   Log.d("ERROR", "handleSubAlreadyPurchase: ");

               }
       }
       if (purchases.getPurchaseState() == Purchase.PurchaseState.UNSPECIFIED_STATE){
           Log.d("ERROR", "handleSubAlreadyPurchase: ");
       }

    }

    @Override
    public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) {

        if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list !=null)
        {
            rangopremium.setVisibility(View.VISIBLE);
            statuspremium.setVisibility(View.GONE);
            recyclerView_sub.setVisibility(View.GONE);
            documentReference.update("premium", "si");
            documentReference.update("status", "Vinorrero");
            Log.d("ERROR", "onPurchasesUpdated: " + billingResult.getResponseCode());

             for (Purchase purchase:list)

                 handleSubAlreadyPurchase(purchase);

        }else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED)
            {
                Log.d("ERROR", "onPurchasesUpdated: " + billingResult.getResponseCode());
                rangopremium.setVisibility(View.GONE);
                statuspremium.setVisibility(View.VISIBLE);
                recyclerView_sub.setVisibility(View.VISIBLE);
                documentReference.update("premium", "no");
                documentReference.update("status", "user");
            }else
                {
                    Log.d("ERROR", "onPurchasesUpdated: " + billingResult.getResponseCode());

                }

    }

MySubAdapter.java

public class MySubAdapter extends RecyclerView.Adapter<MySubAdapter.MyViewHolder> {

    AppCompatActivity appCompatActivity;
    List<SkuDetails> skuDetailsList;
    BillingClient billingClient;

    public MySubAdapter(AppCompatActivity appCompatActivity, List<SkuDetails> skuDetailsList, BillingClient billingClient) {
        this.appCompatActivity = appCompatActivity;
        this.skuDetailsList = skuDetailsList;
        this.billingClient = billingClient;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new MyViewHolder(LayoutInflater.from(appCompatActivity.getBaseContext())
                .inflate(R.layout.listado_sub, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {

        holder.txt_sub_name.setText(skuDetailsList.get(position).getTitle());
        holder.txt_precio_sub.setText(skuDetailsList.get(position).getPrice());

        holder.setListener(new IReciclerClickListener() {
            @Override
            public void onClick(View view, int position) {
                BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                        .setSkuDetails(skuDetailsList.get(position))
                        .build();
                int reponse = billingClient.launchBillingFlow(appCompatActivity, billingFlowParams)
                        .getResponseCode();

                switch(reponse)
            {
                case BillingClient.BillingResponseCode.BILLING_UNAVAILABLE:
                    Log.d("ERROR11", "BILLING_UNAVAILABLE");
                    break;
                case BillingClient.BillingResponseCode.DEVELOPER_ERROR:
                    Log.d("ERROR12", "DEVELOPER_ERROR");

                    break;
                case BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED:
                    Log.d("ERROR13", "FEATURE_NOT_SUPPORTED");

                    break;
                case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED:
                    Log.d("ERROR14", "ITEM_ALREADY_OWNED");

                    break;
                case BillingClient.BillingResponseCode.SERVICE_DISCONNECTED:
                    Log.d("ERROR15", "SERVICE_DISCONNECTED");

                    break;
                case BillingClient.BillingResponseCode.SERVICE_TIMEOUT:
                    Log.d("ERROR16", "SERVICE_TIMEOUT");

                    break;
                case BillingClient.BillingResponseCode.ITEM_UNAVAILABLE:
                    Log.d("ERROR17", "ITEM_UNAVAILABLE");

                    break;
                default:
                    break;
            }
            }
        });

    }

    @Override
    public int getItemCount() {
        return skuDetailsList.size();
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        TextView txt_sub_name, txt_precio_sub;
        IReciclerClickListener listener;

        public void setListener(IReciclerClickListener listener) {
            this.listener = listener;
        }

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);

            txt_sub_name = itemView.findViewById(R.id.txt_sub_name);
            txt_precio_sub = itemView.findViewById(R.id.txt_precio_sub);

            itemView.setOnClickListener(this);

        }

        @Override
        public void onClick(View v) {

            listener.onClick(v, getAdapterPosition());

        }
    }

listado_sub.xml

<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_sub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardBackgroundColor="@android:color/transparent"
    card_view:cardElevation="0dp"
    android:theme="@style/Theme.MaterialComponents.Light"
    android:layout_margin="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="10dp"
        android:layout_marginStart="10dp"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:background="@drawable/btn_desing"
            android:padding="16dp">

            <TextView
                android:id="@+id/txt_sub_name"
                android:text="Titulo"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:textColor="@color/colorPrimary"
                android:textSize="16sp"/>

            <TextView
                android:id="@+id/txt_precio_sub"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:layout_gravity="center"
                android:text="Precio"
                android:textAppearance="?attr/textAppearanceBody2"
                android:textColor="?android:attr/textColorSecondary"/>


        </LinearLayout>

    </LinearLayout>

</com.google.android.material.card.MaterialCardView>

Activity_suscripcion.xlm

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/Snackbar_apoyo"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/fondocurva"
    android:orientation="vertical"
    android:layout_gravity="center"
    android:gravity="center">

    <TextView
        android:id="@+id/txtclosesub"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_gravity="end"
        android:layout_marginBottom="20dp"
        android:layout_marginEnd="20dp"
        android:layout_marginTop="20dp"
        android:background="@drawable/circulo"
        android:gravity="center"
        android:text="@string/equis"
        android:textColor="@android:color/background_light"
        android:textStyle="bold" />

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:gravity="center">

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/statuspremium"
                style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="start"
                android:gravity="center"
                android:shadowColor="@color/negro"
                android:shadowDx="2"
                android:shadowDy="5"
                android:visibility="gone"
                android:shadowRadius="10"
                android:text="@string/no_premium"
                android:textColor="@color/colorAccent"
                android:textSize="25sp"
                android:textStyle="bold|italic" />

            <com.hanks.htextview.rainbow.RainbowTextView
                android:id="@+id/rangopremium"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:visibility="gone"
                android:textSize="25sp"
                android:textStyle="bold"
                android:text="PREMIUM"
                app:colorSpace="150dp"
                app:colorSpeed="10dp"/>

            <ImageView
                android:contentDescription="@string/app_name"
                android:layout_width="200dp"
                android:layout_height="200dp"
                android:src="@drawable/vinoayuda"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/haste_premium"
                android:textSize="18sp"
                android:textColor="@color/colorAccent"
                android:layout_gravity="center"
                android:gravity="center"
                android:paddingLeft="20dp"
                android:paddingRight="20dp"
                android:layout_marginBottom="20dp"
                android:textStyle="bold"
                android:fontFamily="sans-serif-smallcaps"
                android:shadowColor="@color/negro"
                android:shadowRadius="10"
                android:shadowDx="2"
                android:shadowDy="5"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/usuario_premium_garantizamos"
                android:textSize="14sp"
                android:textColor="@color/blanco"
                android:layout_gravity="center"
                android:gravity="center"
                android:paddingLeft="20dp"
                android:paddingRight="20dp"
                android:layout_marginBottom="20dp"
                android:textStyle="bold"
                android:fontFamily="sans-serif-smallcaps"
                app:drawableLeftCompat="@drawable/ic_baseline_error_24" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerview_sub"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:visibility="visible"
                android:layout_weight="1"
                android:layout_marginBottom="20dp">

            </androidx.recyclerview.widget.RecyclerView>



        </LinearLayout>

    </androidx.core.widget.NestedScrollView>

</LinearLayout>

Upvotes: 0

Views: 137

Answers (1)

CromSoldier
CromSoldier

Reputation: 57

I know that's quite an old topic but I'm posting my solution here cause I faced the same issue and perhaps it will help someone.

I don't know the reason why but I had to change my architecture. Instead of putting all the specific Billing's function call in the activity, I followed a "MVVM like" implementation. All my Billing calls are in a dedicated BillingClientWrapper class called by a BillingViewModel class that is called by my Activity. So it follows like that:

Activity → BillingViewModel → BillingClientWrapper

I used the official Billing's GitHub repo which has a similar approach: https://github.com/android/play-billing-samples

At the date of my post the implementation in the repo was done with Billing v4 and we are at v5. A bit of adaptation is needed cause some methods are deprecated.

Upvotes: 0

Related Questions