-1

I saw a couple of threads about this frequent error but no one can solve mine (even after trying solutions), I want my code to display the component with data I load from API with like an equivalent to Flatlist in React Native :

Activity I use for "product" component which is a card:

<?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 I use for 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>

My Adapter:

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
    }

}

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

A photo of the result I got:

enter image description here

JSON data from 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}
therealwalim
  • 252
  • 1
  • 4
  • 18
  • 2
    Does this answer your question? [recyclerview No adapter attached; skipping layout](https://stackoverflow.com/questions/29141729/recyclerview-no-adapter-attached-skipping-layout) – Zain Jun 02 '21 at 15:40
  • @Zain I chose the answer below from Shivam Pokhriyal, the problem is solved – therealwalim Jun 02 '21 at 15:43

1 Answers1

3

You'll need to modify your activity so that you're assigning an adapter to your recycler view when the UI is being drawn rather than waiting till you get the result.

Modify your adapter declaration to this:

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

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

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

So, in your onCreate method in the activity, add this at the end of the method:

myadapter = MyAdapter(baseContext)
recyprod.adapter = myadapter

And finally, in your fetchPost onResponse callback, replace this:

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

with this:

myadapter.setProductList(responseBody!!.products)
myadapter.notifyDataSetChanged()
Shivam Pokhriyal
  • 1,044
  • 11
  • 26
  • Sorry, where do I need to add these lines : ```myadapter = MyAdapter(baseContext) recyprod.adapter = myadapter``` because it shows an error " No value passed for parameter 'productList' ", same for adapter, and on activity when I replace what you told me I get "Type mismatch : required ProductRespond found List" – therealwalim Jun 02 '21 at 15:10
  • Edited my answer, Please check again! @iamwalim – Shivam Pokhriyal Jun 02 '21 at 15:16
  • Sorry that's my fault, it was a layout issue, thanks for the time you gived to help me – therealwalim Jun 02 '21 at 15:25