admin管理员组

文章数量:1297115

I am trying to build a list with a recycler view. I created the recycler view, an adapter and set the adapter with default values in OnCreate and then later in that function I call a firebase async function that populates it correctly. Currently OnCreate is not even being called and I am getting the error "No adapter attached; skipping layout"

CHAT ADAPTER CLASS

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
}

And finally here is the code that sets the adapter after the api call

    val adapter = ChatAdapter(messages, this)
                                    chatAdapter = adapter
                                    recyclerView.adapter = chatAdapter
                                    recyclerView.scrollToPosition(messages.size - 1)
                                    chatAdapter.notifyDataSetChanged()

I am trying to build a list with a recycler view. I created the recycler view, an adapter and set the adapter with default values in OnCreate and then later in that function I call a firebase async function that populates it correctly. Currently OnCreate is not even being called and I am getting the error "No adapter attached; skipping layout"

CHAT ADAPTER CLASS

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
}

And finally here is the code that sets the adapter after the api call

    val adapter = ChatAdapter(messages, this)
                                    chatAdapter = adapter
                                    recyclerView.adapter = chatAdapter
                                    recyclerView.scrollToPosition(messages.size - 1)
                                    chatAdapter.notifyDataSetChanged()
Share Improve this question edited Feb 11 at 17:50 Doug Stevenson 318k36 gold badges454 silver badges472 bronze badges Recognized by Google Cloud Collective asked Feb 11 at 17:39 Ron Jones JrRon Jones Jr 231 silver badge3 bronze badges 2
  • 1. No need to create and assign a new adapter to recyclerview after the api call. Just keep the list property inside the adapter and create a method there to update the list. 2. First notifyDataSetChanged() then call scrollToPosition with recyclerView.post { //here } Bonus: onBindViewHolder could be optimized. some computation is going on there. – Abhishek Tiwari Commented Feb 11 at 22:17
  • You MainActivity's onCreate is never called? – Alex Mamo Commented Feb 16 at 5:13
Add a comment  | 

1 Answer 1

Reset to default 0

If you provided the full error from Logcat, it would be easier to help.

You don’t need to create a new adapter after the API call. Instead, initialize the adapter once in onCreate() and assign it to the RecyclerView.

To update the list when new data arrives, modify the existing list inside the adapter rather than replacing the entire adapter.

Since the list is passed via the constructor, a better approach is to define a variable inside the adapter and update it whenever needed.

Additionally, you can implement a setter for the list that updates the data and automatically calls notifyDataSetChanged(), ensuring efficient updates to the RecyclerView.

Adapter:

class ChatAdapter(val conts: Context) : RecyclerView.Adapter<ChatAdapter.ChatViewHolder>() {

var list = mutableListOf<MessageViewModel>()
    set(value) {
        field = value
        notifyDataSetChanged()
    }

// ...

}

After setting the new list, you can also call recyclerView.scrollToPosition(messages.size - 1)

本文标签: androidActivity with RecyclerView not calling OnCreateStack Overflow