You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore数据库数据无法更新求助 - 仿Goodreads校园项目

相关代码

MainActivity.kt

class MainActivity : AppCompatActivity(),BookRecyclerAdapter.ContentListener {
    private lateinit var recyclerAdapter: BookRecyclerAdapter
    private val db = Firebase.firestore

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(layout.activity_main)
        val recyclerView = findViewById<RecyclerView>(id.booksList)

        db.collection("books")
            .get()
            .addOnSuccessListener {
                val items: ArrayList<Book> = ArrayList()
                for (data in it.documents) {
                    val book = data.toObject(Book::class.java)
                    if (book != null) {
                        book.id = data.id
                        items.add(book)
                    }
                }
                recyclerAdapter = BookRecyclerAdapter(items, this@MainActivity)
                recyclerView.apply {
                    layoutManager = LinearLayoutManager(this@MainActivity)
                    adapter = recyclerAdapter
                }
            }.addOnFailureListener { exception ->
                Log.w("MainActivity", "Error getting documents", exception)
            }
    }

    override fun onItemButtonClick(index: Int, item: Book, clickType: ItemClickType) {
        if (clickType == ItemClickType.SAVE) {
            db.collection("books").document(item.id)
                .set(item)
                .addOnSuccessListener { Log.d(TAG, "DocumentSnapshot successfully written!") }
                .addOnFailureListener { e ->
                    Log.w(TAG, "Error writing document", e)
                }
        }
        else if (clickType == ItemClickType.REVIEW) {
            val newFragment: Fragment = ReviewFragment()
            val transaction: FragmentTransaction? = supportFragmentManager.beginTransaction()
            transaction?.replace(R.id.container, newFragment);
            transaction?.addToBackStack(null);
            transaction?.commit();
        }
    }
}

BookRecyclerAdapter.kt

package hr.ferit.enasalaj.zavrsni

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide

enum class ItemClickType {
    SAVE,
    REVIEW
}

class BookRecyclerAdapter(
    val items:ArrayList<Book>,
    val listener: ContentListener,
): RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val mainView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_view_books, parent, false)
        val reviewView = LayoutInflater.from(parent.context).inflate(R.layout.review, parent, false)
        return BookViewHolder(mainView, reviewView)
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (holder) {
            is BookViewHolder -> holder.bind(position, listener, items[position])
        }
    }
    override fun getItemCount(): Int {
        return items.size
    }

    class BookViewHolder(val view: View,val review: View): RecyclerView.ViewHolder(view) {
        private val bookImage = view.findViewById<ImageView>(R.id.image)
        private val bookAuthor = view.findViewById<EditText>(R.id.bookAuthor)
        private val bookTitle = view.findViewById<EditText>(R.id.bookTitle)
        private val bookRating = view.findViewById<EditText>(R.id.bookRating)
        private val reviewButton = view.findViewById<Button>(R.id.writeReviewButton)
        public val saveButton = review.findViewById<Button>(R.id.saveButton)
        public val bookReview = review.findViewById<EditText>(R.id.saveReview)

        fun bind(index: Int, listener: ContentListener, item: Book) {
            Glide.with(view.context).load(item.image).into(bookImage)
            bookAuthor.setText(item.author)
            bookTitle.setText(item.title)
            bookRating.setText(item.rating)
            bookReview.setText(item.review)

            reviewButton.setOnClickListener {
                listener.onItemButtonClick(index,item,ItemClickType.REVIEW)
            }

            saveButton.setOnClickListener{
                listener.onItemButtonClick(index,item,ItemClickType.SAVE)
            }
        }
    }

    interface ContentListener {
        fun onItemButtonClick(index: Int, item: Book, clickType: ItemClickType)
    }
}

build.gradle (Module level)

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'com.google.gms.google-services'
}

android {
    namespace 'hr.ferit.enasalaj.zavrsni'
    compileSdk 32

    defaultConfig {
        applicationId "hr.ferit.enasalaj.zavrsni"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.5.1'
    implementation 'com.google.android.material:material:1.7.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation 'com.google.firebase:firebase-firestore-ktx:24.4.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.4'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
    implementation 'com.github.bumptech.glide:glide:4.14.2'
    implementation "com.google.firebase:firebase-auth:9.6.1"
    implementation 'com.google.firebase:firebase-database:9.6.1'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
    apply plugin: 'com.google.gms.google-services'
}

问题分析与解决方案

核心问题

  1. Save按钮绑定错误:你在RecyclerView的ViewHolder里初始化了Review布局的Save按钮,但Review布局属于Fragment,ViewHolder里的这个按钮根本不在当前显示的界面上,点击事件自然无法触发。
  2. 未传递书籍数据到Fragment:打开ReviewFragment时没有把当前选中的书籍对象传过去,导致Fragment不知道要更新哪本书的评论。
  3. 未获取最新评论内容:即使触发了保存逻辑,也没有从输入框读取用户刚写的评论,直接复用了原Book对象,等于没有更新数据。
  4. Firebase依赖版本不兼容:Auth和Database的版本(9.6.1)远低于Firestore的24.4.1,可能导致运行时冲突。

修正步骤

1. 重构ReviewFragment,处理保存逻辑

class ReviewFragment : Fragment() {
    private lateinit var currentBook: Book
    private lateinit var db: FirebaseFirestore

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        db = Firebase.firestore
        // 接收传递的书籍数据
        arguments?.let {
            currentBook = it.getParcelable("BOOK_DATA")!!
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.review, container, false)
        val saveBtn = view.findViewById<Button>(R.id.saveButton)
        val reviewEt = view.findViewById<EditText>(R.id.saveReview)

        // 初始化显示已有评论
        reviewEt.setText(currentBook.review)

        saveBtn.setOnClickListener {
            val newReview = reviewEt.text.toString().trim()
            // 更新书籍的评论字段
            currentBook.review = newReview
            // 保存到Firestore
            db.collection("books").document(currentBook.id)
                .set(currentBook)
                .addOnSuccessListener {
                    Toast.makeText(context, "评论保存成功", Toast.LENGTH_SHORT).show()
                    // 返回列表页
                    parentFragmentManager.popBackStack()
                }
                .addOnFailureListener { e ->
                    Log.w("ReviewFragment", "保存失败", e)
                    Toast.makeText(context, "保存失败:${e.message}", Toast.LENGTH_SHORT).show()
                }
        }
        return view
    }

    companion object {
        // 静态方法,用于传递书籍数据
        fun newInstance(book: Book): ReviewFragment {
            val fragment = ReviewFragment()
            val args = Bundle()
            args.putParcelable("BOOK_DATA", book)
            fragment.arguments = args
            return fragment
        }
    }
}

2. 修改MainActivity打开Fragment的逻辑

else if (clickType == ItemClickType.REVIEW) {
    val newFragment = ReviewFragment.newInstance(item)
    supportFragmentManager.beginTransaction()
        .replace(R.id.container, newFragment)
        .addToBackStack(null)
        .commit()
}

3. 让Book类实现Parcelable接口

因为要传递Book对象,需要实现Parcelable:

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class Book(
    var id: String = "",
    var title: String = "",
    var author: String = "",
    var rating: String = "",
    var image: String = "",
    var review: String = ""
) : Parcelable

4. 清理Adapter中的错误绑定

删除Adapter中关于Review布局的所有代码,修改后的关键部分:

// onCreateViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    val mainView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_view_books, parent, false)
    return BookViewHolder(mainView)
}

// BookViewHolder
class BookViewHolder(val view: View): RecyclerView.ViewHolder(view) {
    private val bookImage = view.findViewById<ImageView>(R.id.image)
    private val bookAuthor = view.findViewById<EditText>(R.id.bookAuthor)
    private val bookTitle = view.findViewById<EditText>(R.id.bookTitle)
    private val bookRating = view.findViewById<EditText>(R.id.bookRating)
    private val reviewButton = view.findViewById<Button>(R.id.writeReviewButton)

    fun bind(index: Int, listener: ContentListener, item: Book) {
        Glide.with(view.context).load(item.image).into(bookImage)
        bookAuthor.setText(item.author)
        bookTitle.setText(item.title)
        bookRating.setText(item.rating)

        reviewButton.setOnClickListener {
            listener.onItemButtonClick(index, item, ItemClickType.REVIEW)
        }
    }
}

5. 统一Firebase依赖版本

更新Auth和Database的版本,将apply plugin移到文件末尾:

dependencies {
    // ... 其他依赖保持不变
    implementation "com.google.firebase:firebase-auth:22.3.0"
    implementation 'com.google.firebase:firebase-database:20.3.0'
}

apply plugin: 'com.google.gms.google-services'

内容的提问来源于stack exchange,提问作者ena9911

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 08:15:36