没有连接适配器;在 Kotlin 上跳过布局

No adapter attached; skipping layout on Kotlin

我看到了几个关于这个常见错误的线程,但没有人能解决我的问题(即使在尝试解决方案之后),我希望我的代码显示组件,其中包含我从 API 加载的数据,就像一个等效的到 React Native 中的平面列表:

Activity 我使用卡片作为“产品”组件:

<?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=".Authenticated">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyprod"
        android:layout_width="409dp"
        android:layout_height="729dp"
        android:layout_marginStart="1dp"
        android:layout_marginLeft="1dp"
        android:layout_marginEnd="1dp"
        android:layout_marginRight="1dp"
        android:layout_marginBottom="2dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Activity 我用于 RecyclerView:

<?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=".Authenticated">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyprod"
        android:layout_width="409dp"
        android:layout_height="729dp"
        android:layout_marginStart="1dp"
        android:layout_marginLeft="1dp"
        android:layout_marginEnd="1dp"
        android:layout_marginRight="1dp"
        android:layout_marginBottom="2dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

我的适配器:

package com.mlp.project.utils

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.mlp.project.api.model.Product
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.mlp.project.R
import kotlinx.android.synthetic.main.activity_product.view.*

class MyAdapter(val context: Context, val productList: List<Product>): RecyclerView.Adapter<MyAdapter.ViewHolder>(){

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        var name: TextView
        var price: TextView
        var productImage: ImageView

        init {
            name = itemView.name
            price = itemView.price
            productImage = itemView.productImage

        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val itemView = LayoutInflater.from(context).inflate(R.layout.activity_product, parent, false)
        return ViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.name.text = productList[position].name
        holder.price.text = productList[position].price.toString()
    }

    override fun getItemCount(): Int {
        return productList.size
    }

}

我的activity:

class Authenticated : AppCompatActivity() {

    private lateinit var sessionManager: SessionManager
    private lateinit var apiClient: ApiClient

    lateinit var myadapter: MyAdapter
    lateinit var linearLayoutManager: LinearLayoutManager

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

        recyprod.setHasFixedSize(true)
        linearLayoutManager = LinearLayoutManager(this)
        recyprod.layoutManager = linearLayoutManager

        fetchPosts()
    }

    private fun fetchPosts() {
        // val count: Number

        apiClient = ApiClient()
        sessionManager = SessionManager(this)

        // Pass the token as parameter
        apiClient.getApiService().fetchPosts(token = "${sessionManager.fetchAuthToken()}")
            .enqueue(object : Callback<ProductResponse> {
                override fun onFailure(call: Call<ProductResponse>, t: Throwable) {
                    d("Authenticated", "onFailure" + t.message)
                }

                override fun onResponse(call: Call<ProductResponse>, response: Response<ProductResponse>) {
                    Log.d("Response", response.toString())

                    val responseBody = response.body()

                    myadapter = MyAdapter(baseContext, responseBody!!.products)
                    recyprod.adapter = myadapter
                }
            })
    }
}

我得到的结果照片:

JSON 数据来自 API:

{
  "products": [
    {
      "name": "Tapas",
      "price": 10,
      "productImage": "uploads\2021-04-04T15-43-36.826Z_tapas.png",
      "_id": "6069dea870f35f0f90242f4a",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/6069dea870f35f0f90242f4a"
      }
    },
    {
      "name": "Cupcake",
      "price": 6,
      "productImage": "uploads\2021-04-04T20-04-27.036Z_detail-5.jpg",
      "_id": "606a1bcba294652bb03e6952",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/606a1bcba294652bb03e6952"
      }
    },
    {
      "name": "Bottle",
      "price": 6,
      "productImage": "uploads/2021-05-23T14-27-33.336Z_Water.jpg",
      "_id": "60aa6655898ea9002454b27f",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/60aa6655898ea9002454b27f"
      }
    },
    {
      "name": "Bottle",
      "price": 6,
      "productImage": "uploads/2021-05-23T14-36-50.590Z_Water.jpg",
      "_id": "60aa688245340b0024735b5c",
      "request": {
        "type": "GET",
        "url": "https://katobackend.azurewebsites.net/api/product/60aa688245340b0024735b5c"
      }
    }
  ]
}

Logcat:

06-02 14:31:15.877 12069-12069/com.mlp.project E/RecyclerView: No adapter attached; skipping layout
06-02 14:31:15.951 12069-12069/com.mlp.project E/RecyclerView: No adapter attached; skipping layout
06-02 14:31:16.050 12069-12069/com.mlp.project D/Response: Response{protocol=h2, code=200, message=, url=https://katobackend.azurewebsites.net/api/product}

您需要修改 activity 以便在绘制 UI 时将适配器分配给回收器视图,而不是等到您获得结果。

将您的适配器声明修改为:

class MyAdapter(val context: Context): RecyclerView.Adapter<MyAdapter.ViewHolder>(){

    private var productList: List<Product> = emptyList()

    fun setProductList(list: List<Product>) {
        productList = list
    }

因此,在 activity 中的 onCreate 方法中,在方法末尾添加:

myadapter = MyAdapter(baseContext)
recyprod.adapter = myadapter

最后,在您的 fetchPost onResponse 回调中,替换为:

myadapter = MyAdapter(baseContext, responseBody!!.products)
recyprod.adapter = myadapter

有了这个:

myadapter.setProductList(responseBody!!.products)
myadapter.notifyDataSetChanged()