RecyclerView报错No adapter attached: skipping layout,故事列表无法显示
问题描述
开发故事列表展示的主页面,登录成功后已成功获取API返回的token,但故事列表无法显示,报错:
no adapter attached: skipping layout
相关代码如下:
@Suppress("DEPRECATION") @AndroidEntryPoint class MainActivity : AppCompatActivity() { companion object{ const val EXTRA_TOKEN = "extra_token" } private var binding: ActivityMainBinding? = null private var token: String = " " private lateinit var recyclerView: RecyclerView private lateinit var listAdapter: StoryAdapter private val mainViewModel: MainViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding?.root) token = intent.getStringExtra(EXTRA_TOKEN).toString() // Didn't I define the recyclerView first? Why is it still an error? listAdapter = StoryAdapter() recyclerView = binding?.rvStory!! recyclerView.adapter = listAdapter lifecycleScope.launchWhenCreated { launch { mainViewModel.getAuthToken().collect {itToken -> if (!itToken.isNullOrEmpty()) token = itToken getAllStories(token) setSwipeLayout() } } } binding?.fabAddStory?.setOnClickListener{ Intent(this, AddStoryActivity::class.java).also { intent -> startActivity(intent) } } } private fun setSwipeLayout(){ binding?.srLayout?.setOnRefreshListener { getAllStories(token) binding!!.srLayout.isRefreshing = false } } private fun getAllStories(token:String){ lifecycleScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { mainViewModel.getAllStories(token).collect{ result -> result.onSuccess { val response = result.getOrNull() val liststory = response?.listStory as List<ListStoryItem> Log.d("MainActivity", "List Story Size: ${liststory.size}") setupRecyclerView() setUpadateStories(liststory) } result.onFailure { val response = result.exceptionOrNull() response?.printStackTrace() } } } } } private fun setUpadateStories(liststory: List<ListStoryItem>){ val recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState() listAdapter.submitList(liststory) recyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState) } private fun setupRecyclerView() { recyclerView = binding?.rvStory!! recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = listAdapter } }
错误截图显示上述报错提示。
问题分析与解决
核心问题
RecyclerView正常工作必须同时配置Adapter和LayoutManager,你的代码在onCreate中只给RecyclerView设置了Adapter,却把LayoutManager的配置放在接口请求成功后的setupRecyclerView方法里。页面初始化阶段RecyclerView缺少LayoutManager,系统就会抛出no adapter attached: skipping layout错误(提示存在误导,实际是缺少LayoutManager导致)。
另外,setupRecyclerView里重复执行recyclerView = binding?.rvStory!!属于冗余操作,可能引发不必要的视图绑定问题。
修改方案
- 提前初始化LayoutManager
在onCreate中初始化RecyclerView时,同时设置好LayoutManager,无需等待接口返回数据:
// onCreate中的初始化代码修改为: listAdapter = StoryAdapter() recyclerView = binding?.rvStory!! recyclerView.layoutManager = LinearLayoutManager(this) // 提前设置LayoutManager recyclerView.adapter = listAdapter
- 移除冗余的setupRecyclerView方法调用
既然已经在onCreate中完成RecyclerView初始化,接口请求成功后直接调用setUpadateStories更新数据即可,删掉setupRecyclerView()调用:
// getAllStories中的成功回调修改为: result.onSuccess { val response = result.getOrNull() val liststory = response?.listStory as List<ListStoryItem> Log.d("MainActivity", "List Story Size: ${liststory.size}") // 删掉setupRecyclerView() setUpadateStories(liststory) }
- 优化生命周期调用
getAllStories中使用repeatOnLifecycle(Lifecycle.State.RESUMED)会限制数据收集时机,改成Lifecycle.State.STARTED更合理,能在页面可见时就开始数据请求:
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { mainViewModel.getAllStories(token).collect{ result -> // ... 原有逻辑 } }
- 修正token初始化逻辑
onCreate中直接用intent.getStringExtra(EXTRA_TOKEN).toString()可能得到空字符串(如果intent中无该值),建议添加空值判断:
token = intent.getStringExtra(EXTRA_TOKEN) ?: ""
最终关键代码片段
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding?.root) // 修正token初始化 token = intent.getStringExtra(EXTRA_TOKEN) ?: "" // 完整初始化RecyclerView listAdapter = StoryAdapter() recyclerView = binding?.rvStory!! recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = listAdapter lifecycleScope.launchWhenCreated { mainViewModel.getAuthToken().collect { itToken -> itToken?.takeIf { it.isNotEmpty() }?.let { token = it } getAllStories(token) setSwipeLayout() } } // ... 其余点击事件逻辑 } private fun getAllStories(token:String){ lifecycleScope.launch { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { mainViewModel.getAllStories(token).collect{ result -> result.onSuccess { val response = result.getOrNull() val liststory = response?.listStory as List<ListStoryItem> Log.d("MainActivity", "List Story Size: ${liststory.size}") setUpadateStories(liststory) } result.onFailure { it.printStackTrace() } } } } }
额外提示
- 确保
StoryAdapter正确实现ListAdapter或RecyclerView.Adapter的核心方法(如onCreateViewHolder、onBindViewHolder),避免Adapter自身问题导致列表不显示。 - 若无特殊滚动位置需求,可去掉
setUpadateStories中布局状态保存与恢复的逻辑,submitList本身会自动处理列表更新。
内容的提问来源于stack exchange,提问作者HoonBee
相关产品推荐
相关产品推荐

