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

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!!属于冗余操作,可能引发不必要的视图绑定问题。

修改方案

  1. 提前初始化LayoutManager
    在onCreate中初始化RecyclerView时,同时设置好LayoutManager,无需等待接口返回数据:
// onCreate中的初始化代码修改为:
listAdapter = StoryAdapter()
recyclerView = binding?.rvStory!!
recyclerView.layoutManager = LinearLayoutManager(this) // 提前设置LayoutManager
recyclerView.adapter = listAdapter
  1. 移除冗余的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)
}
  1. 优化生命周期调用
    getAllStories中使用repeatOnLifecycle(Lifecycle.State.RESUMED)会限制数据收集时机,改成Lifecycle.State.STARTED更合理,能在页面可见时就开始数据请求:
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
    mainViewModel.getAllStories(token).collect{ result ->
        // ... 原有逻辑
    }
}
  1. 修正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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 03:01:07