Reputation: 23
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()
Upvotes: 0
Views: 46
Reputation: 33
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)
Upvotes: 0