简体   繁体   中英

Complex and nested firebase realtime database reading with firebase recycler adapter

在此处输入图像描述

The first data node that is immediately there under user id will contain a linked list type data. Each index can contain two parts: data and info. The confusion is due to the unique key -MkqHbtLzqzI... which is there immediately under index data. Each index data will have a list of such a different and dynamic key. Matrix is a List<Float> .

We want to use FirebaseRecyclerAdapter where I will be required to give the type of class under setQuery method. But I am confused how to make equivalent pojo class (or data class in kotlin) of such a structure.

Objects that we want to load in a recyclerView starts from 2 . So, 6154... is a userId under which we have a node called data as shown in the given screenshot. This data contains a list of items in a linkedList<Long> fashion that we want to display in a recyclerView .

I have tried with below data classes but the problem is, it neither contains the index ( 2 in screenshot) nor the unique key ( -MkqH... ).

UserData ( A class that I am using for firebaseRecyclerViewAdapter )

@Keep
@IgnoreExtraProperties
data class UserData(
    var data: UserPrefsData? = null,
    var info: UserPrefsInfo? = null
) {
    @Exclude
    fun toMap(): Map<String, Any?> {
        return mapOf(
            "data" to data,
            "info" to info
        )
    }
}

UserPrefsData

@Keep
@IgnoreExtraProperties
data class UserPrefsData(
    var color: String = BRUSH_BLACK,
    var stroke: Float = 8f,
    var data: String = "",
    var shape: Shape? = null,
    var fill: Boolean = false,
    var matrix : ArrayList<Float>? = null
) {
    @Exclude
    fun toMap(): Map<String, Any?> {
        return mapOf(
            "color" to color,
            "stroke" to stroke,
            "data" to data,
            "shape" to shape,
            "fill" to fill,
            "matrix" to matrix
        )
    }
}

UserPrefsInfo

@Keep
@IgnoreExtraProperties
data class PageInfo(
     var color: String = BRUSH_WHITE,
    var backGround: BackGround = BackGround.COLOR,
    var orientation: Int = ORIENTATION_PORTRAIT,
    var previous: Int = -1,
    var next: Int = -1
) {
    @Exclude
    fun toMap(): Map<String, Any?> {
        return mapOf(
            "color" to color,
            "backGround" to backGround,
            "orientation" to orientation,
            "previous" to previous,
            "next" to next
        )
    }
}

Activity

 private fun initFirebaseAdapter(): FirebaseAdapter? {
        val userDataRef = databaseReference.child("data")
        val options = FirebaseRecyclerOptions.Builder<UserData>()
            .setLifecycleOwner(this)
            .setQuery(userDataRef, UserData::class.java)
            .build()
        return FirebaseAdapter(
            options,
            isAdmin,
            rvItemEventListener
        )
    }
private fun setRecyclerViewAdapter(
        recyclerView: RecyclerView?,
        recyclerViewAdapter: RecyclerView.Adapter<out RecyclerView.ViewHolder>?
    ) {
        recyclerView?.adapter = recyclerViewAdapter
    }
rvFirebaseAdapter = initFirebaseAdapter()
setRecyclerViewAdapter(binding.idVRv, rvFirebaseAdapter)

FirebaseAdapter

class FirebaseAdapter(var options: FirebaseRecyclerOptions<UserData>,
                                val showDeleteOption: Boolean,
                                private val callbackListener: Callbacks.RecyclerViewItemCallback):
    FirebaseRecyclerAdapter<UserData, FirebaseAdapter.UserViewHolder>(options) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val itemView =
            LayoutInflater.from(parent.context).inflate(R.layout.user_item, parent, false)
        val binding = UserItemBinding.bind(itemView)
        return UserViewHolder(binding, itemView)
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :onBindViewHolder: position: $position item: ${getItem(position)} _getting data here - it is working_")
        if (position != RecyclerView.NO_POSITION) {
            bindData(holder, position)
        }
    }

    private fun bindData(holder: UserViewHolder, position: Int) {
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :bindData: position: $position" _This is also working_)
        holder.binding.idVTvPageNumber.text = (position + 1).toString()
    }

    override fun getItemCount(): Int {
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :superGetItemCount: ${super.getItemCount()}")
        return super.getItemCount()
    }

    inner class UserViewHolder(val binding: UserItemBinding, itemView: View): RecyclerView.ViewHolder(itemView) {
        init {
            if (showDeleteOption) {
                binding.idVIvDelete.setOnClickListener {
                    Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: UserViewHolder: :bindingAdapterPosition: $bindingAdapterPosition absoluteAdapterPosition: $absoluteAdapterPosition" _This is working_)
                    onDeleteItem(adapterPosition, binding.idVIvDelete)
                }
            } else {
                binding.idVIvDelete.visibility = View.GONE
            }
        }
    }

    private fun onDeleteItem(adapterPosition: Int, idVIvDelete: View) {
        if (adapterPosition != RecyclerView.NO_POSITION) {
            Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :onDeleteItem: position: $adapterPosition" _This is also working_)
            val item = getItem(adapterPosition)
            getRef(adapterPosition).removeValue()
            callbackListener.onDeleteItem(adapterPosition, item, idVIvDelete, itemCount)
            notifyItemRemoved(adapterPosition)
        }
    }

    override fun onBindViewHolder(
        holder: UserViewHolder,
        position: Int,
        model: UserData
    ) {
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :onBindViewHolder: firebase: position: $position UserData: $model" _This is never being called_)
        if (position != RecyclerView.NO_POSITION) {
            bindData(holder, position)
        }
    }

    override fun onChildChanged(
        type: ChangeEventType,
        snapshot: DataSnapshot,
        newIndex: Int,
        oldIndex: Int
    ) {
        super.onChildChanged(type, snapshot, newIndex, oldIndex)
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :onChildChanged: snapshot: $snapshot" _This is working_)
    }

    override fun onDataChanged() {
        super.onDataChanged()
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :onDataChanged: ")
    }

    override fun onError(error: DatabaseError) {
        super.onError(error)
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :onError: $error")
    }

    override fun getItem(position: Int): UserData {
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :getItem: position: $position")
        return super.getItem(position)
    }

    override fun getRef(position: Int): DatabaseReference {
        Timber.d(" :$LOG_APP_NAME: FirebaseAdapter: :getRef: position: $position")
        return super.getRef(position)
    }
}

Update: 06th Oct 2021

_The default onBindViewHolder is calling onBindViewHolder of FirebaseRecyclerAdapter and in our implementation, there was no super call. Hence, after removing onBindViewHolder(holder: UserViewHolder, position: Int) , onBindViewHolder(holder: UserViewHolder, position: Int, model: UserData) is getting called. But I still do not know how to get those indices and unique keys .

Thank you in anticipation. Any reference link, suggestion, guidance will also be helpful.

For such nested data, we can use a SnapshotParser . Also, in order to fulfil the requirements, I had to change data class as below:

UserData

@Keep
@IgnoreExtraProperties
data class UserData(

    @Exclude
    var dataIndex: Long? = null,

    @Exclude
    var userDataItemKey: String? = null,

    @Exclude
    var listOfUserPrefsData: MutableList<UserPrefsData?>? = null,

    @JvmField
    @PropertyName(AppFirebase.DATA)
    var data: UserPrefsData? = null,

    @JvmField
    @PropertyName(AppFirebase.INFO)
    var userPrefsInfo: UserPrefsInfo? = null
) {
    @Exclude
    fun toMap(): Map<String, Any?> {
        return mapOf(
            "data" to data,
            "info" to userPrefsInfo
        )
    }
}

After that, I have used SnapshotParser as below:

private fun initFirebaseAdapter(): FirebaseAdapter? {
        val userDataRef = databaseReference.child(AppFirebase.DATA)
        val options = FirebaseRecyclerOptions.Builder<UserData>()
            .setLifecycleOwner(this)
            .setQuery(userDataRef) {
                val userPrefsInfo: UserPrefsInfo?
                var userDataItemKey: String? = null
                val listOfUserPrefsData = mutableListOf<UserPrefsData?>()
                val dataIndex = it.key?.toLong()
                val userPrefsInfoRef = it.child(AppFirebase.INFO)
                userPrefsInfo = userPrefsInfoRef.getValue<UserPrefsInfo>()
                val userPrefsDataRef = it.child(AppFirebase.DATA)
                for (userDataItem in userPrefsDataRef.children) {
                    userDataItemKey = userDataItem.key
                    val userPrefsData = userDataItem.getValue<UserPrefsData>()
                    userPrefsData?.userDataItemKey = userDataItemKey
                    listOfUserPrefsData.add(userPrefsData)
                }
                UserData(
                    dataIndex = dataIndex,
                    userDataItemKey = userDataItemKey,
                    listOfUserPrefsData = listOfUserPrefsData,
                    userPrefsInfo = userPrefsInfo
                )
            }
            .build()
        return FirebaseAdapter(
            options,
            isAdmin,
            rvWhiteboardItemEventListener
        )
    }

Now I have that 2 indices, that list of -Mkq... unique keys including UserPrefsData and UserPrefsInfo for each index. So, basically, everything that is there under data of 6154... including indices and unique keys...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM