E / RecyclerView:未连接适配器;跳过布局-Kotlin Billing

时间:2020-06-04 15:59:00

标签: android xml kotlin android-recyclerview android-adapter

我在结算过程中显示商品存在问题,logcat向我显示 E / RecyclerView:未连接适配器;跳过布局

我尝试了几种方法来解决,但从未成功。

所有代码:

科特琳课

Principal.kt

import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.billingclient.api.*

class Principal : AppCompatActivity(), PurchasesUpdatedListener {

    private lateinit var billingClient: BillingClient
    private lateinit var productsAdapter: ProductsAdapter
    private lateinit var mRecyclerView : RecyclerView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_principal)
        setupBillingClient()

    }

    private fun setupBillingClient() {
        billingClient = BillingClient
            .newBuilder(this)
            .enablePendingPurchases()
            .setListener(this)
            .build()
        billingClient.startConnection(object : BillingClientStateListener {

            override fun onBillingServiceDisconnected() {
                Toast.makeText(this@Principal, "Desconectado", Toast.LENGTH_SHORT).show()
                println("BILLING | onBillingServiceDisconnected | DISCONNECTED")
            }
            override fun onBillingSetupFinished(responseCode: BillingResult) {
                if (responseCode.responseCode == BillingClient.BillingResponseCode.OK) {
                    Toast.makeText(this@Principal, "Conectado", Toast.LENGTH_SHORT).show()
                    println("BILLING | startConnection | RESULT OK")
                    clientReady()
                } else {
                    Toast.makeText(this@Principal, "" + responseCode, Toast.LENGTH_SHORT).show()
                    println("BILLING | startConnection | RESULT: $responseCode")
                }
            }

        })
    }

    private fun initProductAdapter(skuDetailsList: List<SkuDetails>) {
        productsAdapter = ProductsAdapter(skuDetailsList) {
            val billingFlowParams = BillingFlowParams
                .newBuilder()
                .setSkuDetails(it)
                .build()
            billingClient.launchBillingFlow(this, billingFlowParams)
        }
        mRecyclerView = findViewById(R.id.products)
        mRecyclerView.setHasFixedSize(true)
        mRecyclerView.layoutManager = GridLayoutManager(this,2)
        mRecyclerView.adapter = productsAdapter
    }

    private fun clientReady(){
        if (billingClient.isReady) {
            val params = SkuDetailsParams
                .newBuilder()
                .setSkusList(skuList) /*listOf("0_50", "1_00")  -- skuList*/
                .setType(BillingClient.SkuType.INAPP)
                .build()
            billingClient.querySkuDetailsAsync(params) {responseCode, skuDetailsList ->
                if (responseCode.responseCode == BillingClient.BillingResponseCode.OK) {
                    initProductAdapter(skuDetailsList)
                } else {
                    Toast.makeText(this@Principal, "No se han sincronizado los productos",Toast.LENGTH_SHORT).show()
                }
            }
        } else {
            Toast.makeText(this@Principal, "Cliente no preparado",Toast.LENGTH_SHORT).show()
        }
    }

    companion object {
        private val skuList = listOf("0_50", "1_00")
    }

    override fun onPurchasesUpdated(p0: BillingResult?, purchases: MutableList<Purchase>?) {
        Toast.makeText(this@Principal, "Comprado "+purchases!!.size,Toast.LENGTH_SHORT).show()
    }
}

ProductsAdapter.kt

import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.android.billingclient.api.SkuDetails

class ProductsAdapter(
    private val list: List<SkuDetails> ,
    private val onProductClicked: (SkuDetails) -> Unit
) : RecyclerView.Adapter<ProductsAdapter.ViewHolder>() {

    override fun getItemCount(): Int = list.size

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val textView = LayoutInflater.from(parent.context).inflate(R.layout.product_item, parent, false) as TextView
        val viewHolder = ViewHolder(textView)
        textView.setOnClickListener { onProductClicked(list[viewHolder.adapterPosition]) }
        return viewHolder
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.textView.text = list[position].title
    }

    class ViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
}

和xml文件:

activity_principal.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Principal">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="472dp"
        android:text="Bienvenido"
        android:textSize="35sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.497"
        app:layout_constraintStart_toStartOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/products"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scrollbars="vertical"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:spanCount="2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

</androidx.constraintlayout.widget.ConstraintLayout>

product_item.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="#000"
    android:textSize="20sp" />

这是一个经常性的话题,但我看不到正确的答案

谢谢。

2 个答案:

答案 0 :(得分:0)

在调用initProductAdapter之前,将对设置回收站视图的调用从onCreate移至setUpBillingClient

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_principal)
    mRecyclerView = findViewById(R.id.products)
    mRecyclerView.setHasFixedSize(true)
    mRecyclerView.layoutManager = GridLayoutManager(this,2)
    setupBillingClient()
}

这应该可以解决问题。

答案 1 :(得分:0)

问题在于,每次触发querySkuDetailsAsync回调时,您都要初始化适配器。因此,您的recyclerview失去了对其适配器的引用,并且不显示任何布局。 尝试以这种方式重构代码:

class Principal : AppCompatActivity(), PurchasesUpdatedListener {

  val skuDetailsList = arrayListOf()

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_principal)
        setupBillingClient()
        initProductAdapter(skuDetailsList)
  }

然后,在您的回调中,将返回的元素添加到列表中并通知适配器:

private fun clientReady() {
    if (billingClient.isReady) {
        val params = SkuDetailsParams.newBuilder()
                .setSkusList(skuList) /*listOf("0_50", "1_00")  -- skuList*/
                .setType(BillingClient.SkuType.INAPP)
                .build()

        billingClient.querySkuDetailsAsync(params) { responseCode, list ->
            if (responseCode.responseCode == BillingClient.BillingResponseCode.OK) {
                skuDetailsList.clear()
                skuDetailsList.addAll(list)
                productsAdapter.notifyDataSetChanged()
            } else {
                Toast.makeText(this@Principal, "No se 
                        han sincronizado los productos", 
                        Toast . LENGTH_SHORT).show()
            }
        }
    } else {
        Toast.makeText(this@Principal, "Cliente no preparado",
                Toast.LENGTH_SHORT).show()
    }
}
相关问题