【问题标题】:E/RecyclerView: No adapter attached; skipping layout -- Kotlin BillingE/RecyclerView:没有附加适配器;跳过布局——Kotlin Billing
【发布时间】:2020-06-04 15:59:00
【问题描述】:

我在计费流程中显示产品有一些问题,logcat 显示我 E/RecyclerView:未连接适配器;跳过布局

我尝试了几种方法来解决,都不行。

所有代码:

类 Kotlin

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" />

这是一个反复出现的话题,但我看不到正确答案

谢谢。

【问题讨论】:

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


    【解决方案1】:

    在调用setUpBillingClient之前,将设置回收器视图的调用从initProductAdapter移到您的onCreate

    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()
    }
    

    这应该可以解决问题。

    【讨论】:

      【解决方案2】:

      问题是每次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()
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-09
        • 2021-06-19
        相关资源
        最近更新 更多