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

Retrofit获取数据后RecyclerView无法显示内容求助

嘿,我帮你排查了代码里的问题,现在给你一步步拆解修复方案:

问题分析与修复步骤

你遇到的「RecyclerView空白 + No adapter attached; skipping layout」警告,核心是三个地方出了问题,咱们逐个解决:


1. RecyclerView布局时未绑定Adapter

RecyclerView首次绘制的时候,还没被设置任何Adapter,所以系统跳过了布局,哪怕之后数据回来设置了Adapter,也可能不会自动触发重绘。

修复:先绑定空Adapter,再更新数据

首先调整ListFragment.kt的onViewCreated方法顺序,先初始化RecyclerView并绑定空Adapter,再监听数据变化:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    
    // 先搞定RecyclerView的初始化
    recyclerView = binding.rvRepoList // 用ViewBinding直接获取,不用findViewById更靠谱
    recyclerView?.layoutManager = LinearLayoutManager(context)
    recyclerView?.setHasFixedSize(true)
    
    // 先绑定空Adapter,避免布局时无Adapter报错
    listAdapter = ListAdapter(context, emptyList())
    recyclerView?.adapter = listAdapter
    
    // 再监听LiveData的数据更新
    viewModel.getRepos().observe(this, Observer<List<Repo>> { repos ->
        repos?.let {
            this.repoList = it
            Log.i("inside observe","${it.size} repos loaded")
            // 不要每次新建Adapter,直接更新现有Adapter的数据源
            listAdapter.updateData(it)
        }
    })
}

然后给ListAdapter.kt加一个更新数据的方法,用来刷新数据源并通知RecyclerView:

class ListAdapter(private val context: Context?, private var repoList: List<Repo>) : RecyclerView.Adapter<ListAdapter.MyViewHolder>() {
    // ... 保留原有的onCreateViewHolder、getItemCount、onBindViewHolder、MyViewHolder代码
    
    // 添加这个方法,用来更新数据源
    fun updateData(newRepoList: List<Repo>) {
        this.repoList = newRepoList
        notifyDataSetChanged() // 通知RecyclerView数据已更新
    }
}

2. ViewModel里LiveData被重复创建

你的ListViewModel.kt中,每次调用getRepos()都会新建一个MutableLiveData实例:

fun getRepos(): MutableLiveData<List<Repo>>{
    repoList = MutableLiveData() // 这里每次都新建,导致之前的Observer监听失效
    loadRepos()
    return repoList
}

这会导致Fragment监听的LiveData和网络请求回调更新的LiveData不是同一个对象,数据变化根本传不到Fragment里。

修复:只初始化一次LiveData

修改ListViewModel.kt,让repoList只初始化一次:

class ListViewModel : ViewModel() {
    // 只初始化一次LiveData,默认是空列表
    val repoList: MutableLiveData<List<Repo>> = MutableLiveData(emptyList())
    
    fun getRepos(): MutableLiveData<List<Repo>>{
        // 删掉重复创建MutableLiveData的代码
        loadRepos()
        return repoList
    }
    
    private fun loadRepos() {
        Api.RETROFIT_SERVICE.getRepos().enqueue(
            object: Callback<List<Repo>> {
                override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
                    Log.i("Failure: ", t.message ?: "Unknown error occurred")
                }
                override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
                    // 加上response.isSuccessful判断,更严谨
                    if(response.isSuccessful && response.body() != null){
                        repoList.value = response.body()
                        Log.i("response.body :","${response.body()?.size} repos received")
                    }
                }
            })
    }
}

3. 可选优化(让代码更简洁)

既然你已经用了ViewBinding,完全可以丢掉recyclerView这个成员变量,直接用binding.rvRepoList操作,比如在onViewCreated里直接写:

binding.rvRepoList.layoutManager = LinearLayoutManager(context)
binding.rvRepoList.setHasFixedSize(true)
binding.rvRepoList.adapter = listAdapter

这样代码更简洁,也避免了空指针风险。


做完这些修改后,你的RecyclerView应该就能正常加载并显示数据了,那个烦人的「No adapter attached; skipping layout」警告也会消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:02:33