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



我在计费流程中显示产品时遇到一些问题,logcat 显示我E/回收器视图:未连接适配器; 跳过布局

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

所有代码:

科特林类

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

产品适配器.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" />

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

谢谢。

在调用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()
}

这应该可以解决问题。

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

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

最新更新