FirebaseRecyclerAdapter mostra un elemento invece di un array

Nov 05 2020

La mia visualizzazione riciclatore mostra solo l'ultimo elemento nei miei dati. Voglio invece mostrarvi tutto.

Struttura dati:

{
  "messages" : {
    "-MLLiVKuT5anOHM_6x8T" : {
      "senderId" : "[email protected]",
      "senderName" : "Rebecca",
      "text" : "It happens to be where Josh lives",
      "type" : "OUTGOING"
    },
    "-MLLiYGcGhPv3E8xdbyh" : {
      "senderId" : "[email protected]",
      "senderName" : "Rebecca",
      "text" : "But that's not why I'm here",
      "type" : "OUTGOING"
    },
    "-MLLm8JruMp_P99e2-SY" : {
      "senderId" : "[email protected]",
      "senderName" : "Rebecca",
      "text" : "She's a crazy ex-girlfriend",
      "type" : "OUTGOING"
    }
  }
}

Frammento:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    // ...
    val messageManager = LinearLayoutManager(context).apply {
        stackFromEnd = true
    }
    message_list.layoutManager = messageManager

    messageAdapter = MessageAdapter.create(chatViewModel.messagesQuery, viewLifecycleOwner, CURRENT_USER.id)
    message_list.adapter = messageAdapter
}

Visualizza modello:

class ChatViewModel : ViewModel() {

    private val database by lazy { Firebase.database.reference }

    private val messagesRef by lazy { database.child(MESSAGES_CHILD) }

    val messagesQuery: Query by lazy { messagesRef.limitToLast(MESSAGE_LIMIT) }

    val messageTextInput: ObservableField<String> = ObservableField("")

    fun sendMessage() {
        val messageText = messageTextInput.get()
        val message = Message(
            senderId = CURRENT_USER.id,
            senderName = CURRENT_USER.name,
            text = messageText,
            type = Message.Type.OUTGOING
        )
        messagesRef.push().setValue(message)
        messageTextInput.set("")
    }
}

Adattatore:

class MessageAdapter(options: FirebaseRecyclerOptions<Message>) :
    FirebaseRecyclerAdapter<Message, MessageViewHolder>(options) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder =
        when (Message.Type.values()[viewType]) {
            Message.Type.INCOMING -> MessageViewHolder.Incoming.create(parent)
            Message.Type.OUTGOING -> MessageViewHolder.Outgoing.create(parent)
        }

    override fun onBindViewHolder(viewHolder: MessageViewHolder, position: Int, message: Message) {
        Log.d("MessageAdapter#onBindViewHolder", "message: $message") viewHolder.bind(message) } override fun getItemViewType(position: Int): Int = getItem(position).type!!.ordinal companion object { fun create(query: Query, lifecycleOwner: LifecycleOwner, currentUserId: String): MessageAdapter { val parser = SnapshotParser<Message> { val message = it.getValue(Message::class.java) Log.d("MessageAdapter#create", "message: $message")
                message?.id = it.key
                message?.type = if (message?.senderId == currentUserId) {
                    Message.Type.OUTGOING
                } else {
                    Message.Type.INCOMING
                }
                message ?: Message()
            }
            val options =
                FirebaseRecyclerOptions.Builder<Message>()
                    .setQuery(query, parser)
                    .setLifecycleOwner(lifecycleOwner)
                    .build()
            return MessageAdapter(options)
        }
    }
}

Layout del frammento:

<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="viewModel" type="ogbe.eva.bloomer.viewmodels.chat.ChatViewModel"/>
    </data>
    <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".views.chat.ChatFragment">

        <com.google.android.material.appbar.AppBarLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

            <com.google.android.material.appbar.MaterialToolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    style="@style/Widget.MaterialComponents.Toolbar.Primary"/>

        </com.google.android.material.appbar.AppBarLayout>

        <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/message_list"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintBottom_toTopOf="@id/divider"
                    android:layout_margin="@dimen/spacing_md"
                    tools:listitem="@layout/item_message_outgoing"/>

            <View
                    android:id="@+id/divider"
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintBottom_toTopOf="@id/message_text_input"
                    android:background="@color/divider_color"/>

            <EditText
                    android:id="@+id/message_text_input"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toLeftOf="@id/send_message_button"
                    app:layout_constraintBottom_toBottomOf="parent"
                    android:hint="@string/message_text_hint"
                    android:importantForAutofill="no"
                    android:text="@={viewModel.messageTextInput}"
                    style="@style/MessageTextInput"/>

            <com.google.android.material.button.MaterialButton
                    android:id="@+id/send_message_button"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintBottom_toBottomOf="parent"
                    android:layout_marginEnd="@dimen/spacing_md"
                    android:enabled="@{viewModel.isSendButtonEnabled}"
                    android:onClick="@{(view) -> viewModel.sendMessage()}"
                    android:text="@string/send_message_button"/>

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

Layout articolo:

<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable name="message" type="ogbe.eva.bloomer.domain.Message"/>
    </data>
    <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end"
                android:background="@drawable/outgoing_message_bg"
                android:text="@{message.text}"
                android:textIsSelectable="true"
                style="@style/MessageItemText"
                tools:text="It happens to be where Josh lives"/>

    </FrameLayout>
</layout>

L'adattatore sembra elaborare tutti i messaggi nel onBindViewHoldere nel parser, ma viene visualizzato solo un messaggio.

Ho visto questa domanda che è simile ma NON un duplicato. La risposta accettata dice di utilizzare una matrice di valori nel database. Ho provato a importare l'array esatto dalla risposta accettata e ho detto che non era JSON non valido. Se dovrei usare un array, come ne inserisco uno nel database? In caso contrario, in quale altro modo potrei visualizzare l'intera struttura dei dati?

Risposte

1 HaroldSer Nov 05 2020 at 15:03

Prova ad aggiornare il layout del tuo articolo come di seguito.

<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable name="message" type="ogbe.eva.bloomer.domain.Message"/>
    </data>
    <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end"
                android:background="@drawable/outgoing_message_bg"
                android:text="@{message.text}"
                android:textIsSelectable="true"
                style="@style/MessageItemText"
                tools:text="It happens to be where Josh lives"/>

    </FrameLayout>
</layout>

per:

<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable name="message" type="ogbe.eva.bloomer.domain.Message"/>
    </data>
    <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end"
                android:background="@drawable/outgoing_message_bg"
                android:text="@{message.text}"
                android:textIsSelectable="true"
                style="@style/MessageItemText"
                tools:text="It happens to be where Josh lives"/>

    </FrameLayout>
</layout>

Buona programmazione!