RecyclerView所在Activity未触发OnCreate,报错“No adapter attached; skipping layout”
RecyclerView 适配问题:
onCreateViewHolder未触发 + "No adapter attached; skipping layout" 报错 问题描述
我尝试用RecyclerView构建聊天列表,已创建RecyclerView和适配器,在Activity的onCreate方法中为RecyclerView设置默认值,随后调用Firebase异步接口填充数据。现在遇到两个问题:
- 适配器的
onCreateViewHolder方法完全没触发 - 控制台持续报错:
No adapter attached; skipping layout
相关代码
ChatAdapter 代码
class ChatAdapter(private val messages: List<MessageViewModel>, val conts: Context) : RecyclerView.Adapter<ChatAdapter.ChatViewHolder>() { val cont = conts class ChatViewHolder(view: View) : RecyclerView.ViewHolder(view) { val senderTextView: TextView = view.findViewById(R.id.textViewSender) val messageTextView: TextView = view.findViewById(R.id.textViewMessage) val dateTextView: TextView = view.findViewById(R.id.dateTextView) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder { val view = LayoutInflater.from(cont).inflate(R.layout.chat_view_design, parent, false) return ChatViewHolder(view) } @RequiresApi(Build.VERSION_CODES.O) override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { val chatMessage = messages[position] val ref = Firebase.database.reference ref.child("users").child(chatMessage.fromId).get().addOnCompleteListener { task -> if (task.isSuccessful) { val snapshot = task.result val txt = snapshot.child("username").getValue(String::class.java) holder.senderTextView.text = txt } } holder.messageTextView.text = chatMessage.text val instant = Instant.ofEpochMilli((chatMessage.date * 1000).toLong()) val formatter = DateTimeFormatter.ofPattern("MM/dd/yy") val newDate = Date.from(instant) val finalDate : LocalDate = newDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate() holder.dateTextView.text = formatter.format(finalDate) if (messages[position].fromId != Firebase.auth.currentUser?.uid) { holder.senderTextView.setTextColor(Color.parseColor("#FFA500")) } } override fun getItemCount() = messages.size }
Firebase请求后设置适配器的代码
val adapter = ChatAdapter(messages, this) chatAdapter = adapter recyclerView.adapter = chatAdapter recyclerView.scrollToPosition(messages.size - 1) chatAdapter.notifyDataSetChanged()
Activity中初始化RecyclerView的截图

问题原因
No adapter attached报错:RecyclerView在首次布局时,你还在等待Firebase异步请求返回数据,此时没有任何适配器绑定到RecyclerView,系统就会抛出这个警告。onCreateViewHolder未触发:如果直到异步请求完成才绑定适配器,可能此时RecyclerView已经完成了初始布局流程;或者初始绑定的数据源是空列表,且没有正确通知适配器更新。
解决方案
1. 提前在onCreate中绑定空适配器
不要等Firebase请求返回再绑定适配器,先初始化一个空的适配器绑定到RecyclerView,让系统知道RecyclerView有适配器可用,避免报错。
2. 改用可变数据源+适配器更新方法
把适配器的数据源改成MutableList,并添加一个更新数据的方法,这样请求完成后只需要更新数据源并通知适配器刷新,不用重新创建适配器实例,确保RecyclerView能触发onCreateViewHolder。
修改后的代码
优化后的ChatAdapter
class ChatAdapter(private val messages: MutableList<MessageViewModel>, val cont: Context) : RecyclerView.Adapter<ChatAdapter.ChatViewHolder>() { class ChatViewHolder(view: View) : RecyclerView.ViewHolder(view) { val senderTextView: TextView = view.findViewById(R.id.textViewSender) val messageTextView: TextView = view.findViewById(R.id.textViewMessage) val dateTextView: TextView = view.findViewById(R.id.dateTextView) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder { val view = LayoutInflater.from(cont).inflate(R.layout.chat_view_design, parent, false) return ChatViewHolder(view) } @RequiresApi(Build.VERSION_CODES.O) override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { val chatMessage = messages[position] val ref = Firebase.database.reference ref.child("users").child(chatMessage.fromId).get().addOnCompleteListener { task -> if (task.isSuccessful) { val snapshot = task.result val txt = snapshot.child("username").getValue(String::class.java) holder.senderTextView.text = txt } } holder.messageTextView.text = chatMessage.text // 简化日期转换代码 val instant = Instant.ofEpochMilli((chatMessage.date * 1000).toLong()) val formatter = DateTimeFormatter.ofPattern("MM/dd/yy") val finalDate = instant.atZone(ZoneId.systemDefault()).toLocalDate() holder.dateTextView.text = formatter.format(finalDate) if (chatMessage.fromId != Firebase.auth.currentUser?.uid) { holder.senderTextView.setTextColor(Color.parseColor("#FFA500")) } } // 添加更新数据的方法 fun updateMessages(newMessages: List<MessageViewModel>) { messages.clear() messages.addAll(newMessages) notifyDataSetChanged() } override fun getItemCount() = messages.size }
Activity的onCreate修改
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_chat) // 初始化RecyclerView核心配置 recyclerView = findViewById(R.id.recyclerView) recyclerView.layoutManager = LinearLayoutManager(this) // 提前绑定空适配器 val emptyMessages = mutableListOf<MessageViewModel>() chatAdapter = ChatAdapter(emptyMessages, this) recyclerView.adapter = chatAdapter // 发起Firebase请求加载数据 loadChatData() } private fun loadChatData() { // 替换成你实际的Firebase数据查询逻辑 Firebase.database.reference.child("your_chat_messages_path") .addListenerForSingleValueEvent(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { val loadedMessages = mutableListOf<MessageViewModel>() // 解析快照数据到MessageViewModel列表 snapshot.children.forEach { child -> val message = child.getValue(MessageViewModel::class.java) message?.let { loadedMessages.add(it) } } // 更新适配器数据 chatAdapter.updateMessages(loadedMessages) // 滚动到最新消息 recyclerView.scrollToPosition(loadedMessages.size - 1) } override fun onCancelled(error: DatabaseError) { // 这里可以加请求失败的提示处理 } }) }
额外优化建议
- 缓存用户信息:当前
onBindViewHolder中每条消息都发起一次Firebase用户查询,会导致大量重复请求。建议在加载聊天消息时,批量获取所有涉及的用户ID对应的用户名,存入Map<String, String>缓存,在onBindViewHolder中直接从缓存取,提升性能。 - 使用DiffUtil:如果聊天消息量大,用
DiffUtil代替notifyDataSetChanged()可以减少不必要的UI刷新,提升流畅度。
内容的提问来源于stack exchange,提问作者Ron Jones Jr
相关产品推荐
相关产品推荐

