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:
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}