没有连接适配器;在 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()
我看到了几个关于这个常见错误的线程,但没有人能解决我的问题(即使在尝试解决方案之后),我希望我的代码显示组件,其中包含我从 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()