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

