简体   繁体   English

使用 Firestore Kotlin RecyclerView,我试图显示一个自定义 object,它是 class 的一个字段,显示在回收站视图中

[英]Working with a Firestore Kotlin RecyclerView, I am trying to show a custom object which is a field of the class being displayed in the recycler view

I have a Firestore database holding my data.我有一个保存我的数据的 Firestore 数据库。 Here is the structure ( database structure )这是结构(数据库结构

subclass database structure子类数据库结构

So my booking is sub-collections of the user.所以我的预订是用户的子集合。 Each booking contains its own restaurant as a sub-document.每个预订都包含自己的餐厅作为子文档。

Here is the activity file:这是活动文件:


    private lateinit var binding: ActivityMyBookingsBinding

    //recyclerview for list
    lateinit var recyclerView: RecyclerView

    //Firestore
    private var currentUser: FirebaseUser = FirebaseAuth.getInstance().currentUser!!
    private var db: FirebaseFirestore = FirebaseFirestore.getInstance()

    var query: CollectionReference = db
        .collection("Users")
        .document(currentUser.uid)
        .collection("Bookings")

    //adapter
    lateinit var bookingAdapter: BookingItemAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


        binding = ActivityMyBookingsBinding.inflate(layoutInflater)
        val view = binding.root
        setupUI()
        setContentView(view)


        setupRecyclerView()
    }


    private fun setupUI() {
        recyclerView = binding.bookingList
    }


    private fun setupRecyclerView(){

        val options: FirestoreRecyclerOptions<BookingItem> = FirestoreRecyclerOptions.Builder<BookingItem>()
            .setQuery(query, BookingItem::class.java)
            .build()

        bookingAdapter = BookingItemAdapter(this, options)

        recyclerView.layoutManager = LinearLayoutManager(this)

        recyclerView.adapter = bookingAdapter

    }

    override fun onStart() {
        super.onStart()
        bookingAdapter.startListening()
    }

    override fun onStop() {
        super.onStop()
        bookingAdapter.stopListening()
    }

Here is the adapter file这是适配器文件

class BookingItemAdapter(
    val context: Context,
    val options: FirestoreRecyclerOptions<BookingItem>): FirestoreRecyclerAdapter<BookingItem, BookingItemAdapter.BookingViewHolder>(options) {








    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookingViewHolder {
        return BookingViewHolder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.card_booking,
                parent,
                false,
            ),
        )
    }

    @RequiresApi(Build.VERSION_CODES.N)
    override fun onBindViewHolder(holder: BookingViewHolder, position: Int, model: BookingItem) {
        holder.restaurantNameText.booking_restaurant_name.text = model.getRestaurantItem().getName()
        holder.restaurantDistanceText.booking_distance.text = model.getRestaurantItem().getGeoHash()
        holder.restaurantRatingBar.booking_ratingBar.rating = model.getRestaurantItem().getRating()?.toFloat()!!
        holder.bookingDate.booking_date.text = "${model.getDay()}/${model.getMonth()}/${model.getYear()}"
        holder.bookingTime.booking_time.text = "${model.getHour()}:${model.getMinute()}"
        holder.numberGuests.number_guests.text = model.getGuestNumber()

        val url = model.getRestaurantItem().getRestaurantImage()
        Glide
            .with(holder.restaurantImageItem)
            .load(url)
            .into(holder.restaurantImageItem.booking_restaurantImage)

        holder.itemView.setOnClickListener {
            val intent = Intent(context, RestaurantPageActivity::class.java)
            intent.putExtra("model", model.getRestaurantItem())

            context.startActivity(intent)

        }

        CompletableFuture.runAsync {
            runCatching {
                val url = model.getRestaurantItem().getRestaurantImage()
                Glide
                    .with(holder.restaurantImageItem)
                    .load(url)
                    .into(holder.restaurantImageItem.booking_restaurantImage)

            }
        }
    }

    inner class BookingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val restaurantNameText: TextView = itemView.findViewById(R.id.booking_restaurant_name)
        val restaurantImageItem: ImageView = itemView.findViewById(R.id.booking_restaurantImage)
        val restaurantRatingBar: RatingBar = itemView.findViewById(R.id.booking_ratingBar)
        val restaurantDistanceText: TextView = itemView.findViewById(R.id.booking_distance)
        val bookingTime: TextView = itemView.findViewById(R.id.booking_time)
        val bookingDate: TextView = itemView.findViewById(R.id.booking_date)
        val numberGuests: TextView = itemView.findViewById(R.id.number_guests)

    }

Here is the bookingItem class:这是 bookingItem class:

class BookingItem(restaurantItem: RestaurantItem, guestNumber: String, day: String,
                  month: String, year: String, hour: String, minute: String) {

    constructor(): this(RestaurantItem("", "", 0, 0,
            "", "", "", "", false), "", "", "", "", "","")

    private var restaurantItemName = restaurantItem.getName()
    private var restaurantItemImage = restaurantItem.getRestaurantImage()
    private var restaurantItemPrice = restaurantItem.getPrice()
    private var restaurantItemRating = restaurantItem.getRating()
    private var restaurantItemGeohash = restaurantItem.getGeoHash()
    private var restaurantItemLongitude = restaurantItem.getLongitude()
    private var restaurantItemLatitude = restaurantItem.getLatitude()
    private var restaurantItemCuisine = restaurantItem.getCuisine()
    private var restaurantItemDietary = restaurantItem.getDietaryFriendly()
    private var restaurantItem: RestaurantItem = RestaurantItem(
            restaurantItemName,
            restaurantItemImage,
            restaurantItemPrice,
            restaurantItemRating,
            restaurantItemGeohash,
            restaurantItemLongitude,
            restaurantItemLatitude,
            restaurantItemCuisine,
            restaurantItemDietary)

    private var guestNumber: String = guestNumber
    private var day: String = day
    private var month: String = month
    private var year: String = year
    private var hour: String = hour
    private var minute: String = minute



    fun getRestaurantItem(): RestaurantItem{
        this.restaurantItem.getName()
        this.restaurantItem.getRestaurantImage()
        this.restaurantItem.getPrice()
        this.restaurantItem.getRating()
        this.restaurantItem.getGeoHash()
        this.restaurantItem.getLongitude()
        this.restaurantItem.getLatitude()
        this.restaurantItem.getCuisine()
        this.restaurantItem.getDietaryFriendly()
        return this.restaurantItem
    }
    fun getGuestNumber(): String {
        return this.guestNumber
    }

    fun getDay(): String{
        return this.day
    }

    fun getMonth(): String{
        return this.month
    }

    fun getYear(): String{
        return this.year
    }

    fun getHour(): String{
        return this.hour
    }

    fun getMinute(): String{
        return this.minute
    }
}

Finally incase you need it, here is the sub entity - restaurantItem class:最后,如果您需要它,这里是子实体 - restaurantItem class:

class RestaurantItem(name: String, restaurantImage: String, price: Long, rating: Long, geoHash: String ,
                     longitude: String, latitude: String, cuisine: String, dietaryFriendly: Boolean): Parcelable{

    constructor(): this ("", "", 0, 0,
        "", "", "", "", false
    )


    private var name: String = name
    private var restaurantImage: String = restaurantImage
    private var price: Long = price
    private var rating: Long = rating
    private var geoHash: String = geoHash
    private var longitude: String = longitude
    private var latitude: String = latitude
    private var cuisine: String = cuisine
    private var dietaryFriendly: Boolean = dietaryFriendly

    private constructor(parcel: Parcel) : this() {
        name = parcel.readString().toString()
        restaurantImage = parcel.readString().toString()
        price = parcel.readLong()
        rating = parcel.readLong()
        geoHash = parcel.readString().toString()
        longitude = parcel.readString().toString()
        latitude = parcel.readString().toString()
        cuisine = parcel.readString().toString()
        dietaryFriendly = parcel.readByte() != 0.toByte()
    }


    fun getName(): String {
        return this.name
    }
    fun getLatitude(): String {
        return this.latitude
    }
    fun getLongitude(): String {
        return this.longitude
    }
    fun getGeoHash(): String {
        return this.geoHash
    }
    fun getPrice(): Long {
        return this.price
    }
    fun getDietaryFriendly(): Boolean{
        return this.dietaryFriendly
    }
    fun getRating(): Long {
        return this.rating
    }
    fun getRestaurantImage(): String {
        return this.restaurantImage
    }
    fun getCuisine(): String {
        return this.cuisine
    }
    

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(name)
        parcel.writeString(restaurantImage)
        parcel.writeLong(price)
        parcel.writeLong(rating)
        parcel.writeString(geoHash)
        parcel.writeString(longitude)
        parcel.writeString(latitude)
        parcel.writeString(cuisine)
        parcel.writeByte(if (dietaryFriendly) 1 else 0)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<RestaurantItem> {
        override fun createFromParcel(parcel: Parcel): RestaurantItem {
            return RestaurantItem(parcel)
        }

        override fun newArray(size: Int): Array<RestaurantItem?> {
            return arrayOfNulls(size)
        }
    }

Now the data is coming in from firebase fine and the time, date, and a number of guests are being displayed correctly.现在数据从 firebase 进来,时间、日期和客人数量都显示正确。

The restaurant class works because it is used elsewhere and displays correctly in other recycler views.餐厅 class 之所以有效,是因为它在其他地方使用并在其他回收站视图中正确显示。

The issue seems to be that when the booking item is instanciated, all the data in the restaurantItem gets set to its null values.问题似乎是,当预订项目被实例化时,restaurantItem 中的所有数据都设置为其 null 值。

I walked through with the debugger and I can see the data has made it from firebase.我使用调试器进行了检查,我可以看到数据来自 firebase。

This is the data when I debug in the bookingitem constructor and step through这是我在 bookingitem 构造函数中调试并逐步执行时的数据

This is where the data is lost and reset to null values:这是数据丢失并重置为 null 值的地方:

Here is the line that the data is lost这是数据丢失的行

You can access the code here https://github.com/KotaCanchela/RestaurantBookingSystem您可以在此处访问代码https://github.com/KotaCanchela/RestaurantBookingSystem

I appreciate any help that can be provided, I've tried to give as much detail here as possible.我感谢可以提供的任何帮助,我已尝试在此处提供尽可能多的详细信息。

When you are debugging your code, all the properties of the "restaurantItem" object in the debugger are holding the default values because there is no match between the object of the class and the object in Firestore. When you are debugging your code, all the properties of the "restaurantItem" object in the debugger are holding the default values because there is no match between the object of the class and the object in Firestore.

Your "BookingItem" class holds the property called "restaurantItem", while in the database the object is called only "restaurant" , which is not correct.您的“BookingItem” class 拥有名为“restaurantItem”的属性,而在数据库中 object 仅称为“restaurant” ,这是不正确的。 Both names must match.两个名称必须匹配。 You either change the name of the property in the database to be "restaurantItem" and not just "restaurant", or you should use the following annotations:您可以将数据库中的属性名称更改为“restaurantItem”而不仅仅是“restaurant”,或者您应该使用以下注释:

@get:PropertyName("restaurant")
@set:PropertyName("restaurant")
@PropertyName("restaurant")

In front of your restaurantItem property in your "BookingItem" class.在“BookingItem”class 中的restaurantItem属性前面。

Edit:编辑:

According to your comment:根据您的评论:

do you mean in the BookingItem constructor?你的意思是在 BookingItem 构造函数中吗?

Yes.是的。 The minimum implementation for your class might be: class 的最低实现可能是:

data class BookingItem(
        @get:PropertyName("restaurant")
        @set:PropertyName("restaurant")
        @PropertyName("restaurant")
        var restaurantItem: RestaurantItem? = null,
        var guestNumber: String? = null,
        var day: String? = null,
        var month: String? = null,
        var year: String? = null,
        var hour: String? = null,
        var minute: String? = null
)

Where I have initialized those objects with a null value.我用null值初始化了这些对象。 Once you get the data from the database, you'll assign the values to your actual fields.从数据库中获取数据后,您会将值分配给您的实际字段。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我将图像附加到正在从服务器下载的回收器视图中,但是回收器视图未显示任何图像 - I am attaching a image to a recycler view which is being downloaded from server, but recycler view is not showing any image [KOTLIN]我正在尝试将数据从我的回收站视图传递到另一个活动,但不知道如何 - [KOTLIN]I am trying to pass data from my recycler view to another activity but don't know how 我正在尝试使用搜索视图过滤recyclerview,但它无法正常工作 - i am trying to filter recyclerview with search view but it is not working 当我单击另一个recyclerview中的项目时如何显示回收者视图 - How to show recycler view when i click an item in another recyclerview 我正在尝试在 Fragment 中显示 recyclerView,但出现错误 - I am trying to show recyclerView in Fragment but I am getting error 在 Kotlin 中设置 Recycler View,并且不了解如何在没有实例化的情况下在 recyclerView 变量上调用方法 - Setting up Recycler View in Kotlin, and don't understand how methods are being called on recyclerView variable without it being instantiated 尝试将数据从 Firestore 检索到回收站视图 - Trying to retrieve data from firestore into recycler view 我正在尝试从嵌套回收器视图中打开自定义 chrome 选项卡,但无法从 Activity 外部调用 startActivity() 时出错 - I am trying to open custom chrome tab from nested recycler view but couldn't having error Calling startActivity() from outside of an Activity 我有一个User类,它具有一个ArrayList的aprivate字段 <object> ,我希望显示所有ArrayList <object> 在回收者视图中 - I have a User class that has aprivate field a ArrayList<object>, I wish to display all ArrayList<object> in a recycler view 我想在 recyclerview kotlin 中显示空视图数据但错误 - i want to show empty view data in recyclerview kotlin but error
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM