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' }
问题分析与解决方案
核心问题
- Save按钮绑定错误:你在RecyclerView的ViewHolder里初始化了Review布局的Save按钮,但Review布局属于Fragment,ViewHolder里的这个按钮根本不在当前显示的界面上,点击事件自然无法触发。
- 未传递书籍数据到Fragment:打开ReviewFragment时没有把当前选中的书籍对象传过去,导致Fragment不知道要更新哪本书的评论。
- 未获取最新评论内容:即使触发了保存逻辑,也没有从输入框读取用户刚写的评论,直接复用了原Book对象,等于没有更新数据。
- 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
相关产品推荐
相关产品推荐

