You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Retrofit@GET请求数据时遇No adapter attached错误求助

问题:Retrofit获取数据时RecyclerView提示“No adapter attached; skipping layout”

已确认网络正常,RecyclerView的layout_height设为wrap_content,相关代码及布局如下,请求排查原因:

MainActivity代码

package com.example.restart

import android.content.ContentValues.TAG
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.GridLayoutManager
import com.example.restart.api.ApiRequest
import com.example.restart.api.CatalogAdapter
import com.example.restart.api.CatalogModel
import com.example.restart.databinding.ActivityMainBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.Retrofit
import retrofit2.awaitResponse
import retrofit2.converter.gson.GsonConverterFactory

class MainActivity : AppCompatActivity() {
    private var binding: ActivityMainBinding? = null
    private var adapterCatalog = CatalogAdapter()
    lateinit var catalogList: ArrayList<CatalogModel>


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding!!.root)
        getData()
    }
    private lateinit var allblock: List<CatalogModel>

    private fun initCategory(category: List<CatalogModel>) {
        with(binding!!){
            listCatalogInMain.layoutManager = GridLayoutManager(this@MainActivity, 1)
            listCatalogInMain.adapter = adapterCatalog
            var cataloglist: List<CatalogModel> = category
            if(cataloglist.isNotEmpty()){
                for(element in cataloglist){
                    adapterCatalog.addCatalog(element)
                }
            }
        }
    }

    private fun getData(){
        val api = Retrofit.Builder()
            .baseUrl("https://medic.madskill.ru")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiRequest::class.java)

        CoroutineScope(Dispatchers.IO).launch {
            try {
                val response = api.getCatalog().awaitResponse()
                if (response.isSuccessful) {
                    val data = response.body()!!
                    catalogList = data as ArrayList<CatalogModel>
                    runOnUiThread { initCategory(catalogList) }
                    Log.d(TAG, data.toString())
                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    Log.d(TAG, e.toString())
                }
            }
        }
    }
}

ApiRequest代码

import retrofit2.Call
import retrofit2.http.GET

interface ApiRequest {
    @GET("/api/catalog")
    fun getCatalog(): Call<List<CatalogModel>>
}

Adapter代码

package com.example.restart.api

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.restart.R
import com.example.restart.databinding.ItemBlockBinding

class CatalogAdapter: RecyclerView.Adapter<CatalogAdapter.CategoryHolder>() {
    private val listCatalog = ArrayList<CatalogModel>()

    class CategoryHolder(item: View): RecyclerView.ViewHolder(item){
        private var bindingCategory = ItemBlockBinding.bind(item)

        fun bind(category: CatalogModel){
            bindingCategory.name.text = category.name
            bindingCategory.category.text = category.category
            bindingCategory.bio.text = category.bio
            bindingCategory.price.text = category.price
            bindingCategory.timeResult.text = category.time_result
            bindingCategory.preparation.text = category.preparation
            bindingCategory.description.text = category.description
        }
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_block, parent, false)
        return CategoryHolder(view)
    }

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

    override fun onBindViewHolder(holder: CategoryHolder, position: Int) {
        holder.bind(listCatalog[position])
    }

    fun addCatalog(category: CatalogModel){
        listCatalog.add(category)
        notifyDataSetChanged()
    }
}

布局代码

主布局中RecyclerView部分

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/listCatalogInMain"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
    tools:listitem="@layout/item_block">
</androidx.recyclerview.widget.RecyclerView>

Item布局

<?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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    .....
    .....
</androidx.constraintlayout.widget.ConstraintLayout>

问题排查与修复方案

1. 警告核心原因:RecyclerView初始化时机滞后

当前代码里,initCategory是在网络请求成功后才给RecyclerView设置Adapter和LayoutManager,而RecyclerView在页面首次渲染时(onCreate阶段)还没有任何Adapter关联,系统就会抛出这个警告。

修复: 在onCreate中提前初始化RecyclerView,不要等网络请求完成:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding!!.root)
    // 提前初始化RecyclerView的布局管理器和适配器
    binding?.listCatalogInMain?.apply {
        layoutManager = GridLayoutManager(this@MainActivity, 1)
        adapter = adapterCatalog
    }
    getData()
}

然后修改initCategory,只负责更新数据即可:

private fun initCategory(category: List<CatalogModel>) {
    // 先清空旧数据(如果需要刷新而非追加)
    adapterCatalog.listCatalog.clear()
    category.forEach {
        adapterCatalog.addCatalog(it)
    }
}

2. Retrofit协程调用优化

你当前用Call配合awaitResponse(),可以改用suspend函数更贴合协程用法,同时避免不安全的强制转换:

  • 修改ApiRequest接口:
import retrofit2.Response
import retrofit2.http.GET

interface ApiRequest {
    @GET("/api/catalog")
    suspend fun getCatalog(): Response<List<CatalogModel>>
}
  • 修改getData中的调用逻辑:
private fun getData(){
    val api = Retrofit.Builder()
        .baseUrl("https://medic.madskill.ru")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(ApiRequest::class.java)

    CoroutineScope(Dispatchers.IO).launch {
        try {
            val response = api.getCatalog() // 直接调用suspend函数,无需awaitResponse
            if (response.isSuccessful) {
                val data = response.body() ?: return@launch
                catalogList = ArrayList(data) // 安全转换为ArrayList,避免强制转换崩溃
                runOnUiThread { initCategory(catalogList) }
                Log.d(TAG, data.toString())
            }
        } catch (e: Exception) {
            withContext(Dispatchers.Main) {
                Log.d(TAG, e.toString())
            }
        }
    }
}

3. Adapter性能优化

当前逐个添加数据并每次调用notifyDataSetChanged()效率较低,建议新增批量添加方法:

// 在CatalogAdapter中添加
fun addAllCatalog(categories: List<CatalogModel>){
    listCatalog.addAll(categories)
    notifyDataSetChanged()
}

然后在initCategory中直接调用:

private fun initCategory(category: List<CatalogModel>) {
    adapterCatalog.listCatalog.clear()
    adapterCatalog.addAllCatalog(category)
}

4. 布局冗余清理

主布局中已经通过app:layoutManager设置了布局管理器,代码里又重复设置,建议统一一处设置即可,避免冗余。


内容的提问来源于stack exchange,提问作者klmnvan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:39:57