Cloud Firestore 基础
读取和写入实时数据
Cloud Firestore 基础 是 CoddyKit 上的免费 Android Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Android Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Android Academy 课程共包含 4 节课。
什么是 Cloud Firestore?
Cloud Firestore 是 Firebase 提供的灵活且可扩展的 NoSQL 数据库。它将数据存储为归入集合的文档。
- 文档是一组键值字段(类似 JSON 对象)。
- 集合是用于存放文档的容器。
- 文档可以包含子集合,从而形成树状结构。
Firestore 还提供实时更新功能,并且开箱即用地支持离线使用。
获取 Firestore 实例
通过 Firebase.firestore 访问数据库。从这里开始,您可以使用 collection("name") 访问集合,并使用 document("id") 访问具体文档。
创建引用的成本很低 — 引用描述的是一个位置,而不是数据本身。
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
val db = Firebase.firestore
val usersRef = db.collection("users")
val oneUser = db.collection("users").document("abc123")设计数据模型
Firestore 可以很好地映射到 Kotlin 数据类。每个属性都会成为文档中的一个字段。
请为数据类提供一个无参构造函数(使用默认值即可实现),这样 Firestore 才能将文档反序列化回对象。
data class Note(
val title: String = "",
val body: String = "",
val done: Boolean = false,
val createdAt: Long = 0L
)写入文档
使用 set 创建或覆盖文档。使用 add 让 Firestore 生成 ID,或者使用 document(id).set(...) 选择您自己的 ID。
这些调用会返回任务;使用协程时,您可以对它们调用 await()。
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun addNote(note: Note): String {
val ref = Firebase.firestore
.collection("notes")
.add(note) // auto-generated ID
.await()
return ref.id
}读取文档
get() 会读取一次文档。使用 toObject(Note::class.java) 将其转换为您的数据类。
请始终检查 exists() — 对不存在文档的引用会返回一个快照,只是该快照本身不存在。
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun loadNote(id: String): Note? {
val snapshot = Firebase.firestore
.collection("notes")
.document(id)
.get()
.await()
return if (snapshot.exists()) snapshot.toObject(Note::class.java) else null
}更新和删除
update 会修改指定字段,而不会影响文档的其他部分。delete 会彻底删除文档。
如果您希望执行部分写入,并在文档不存在时同时创建它,请使用 set(..., SetOptions.merge())。
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun markDone(id: String) {
Firebase.firestore.collection("notes").document(id)
.update("done", true)
.await()
}
suspend fun removeNote(id: String) {
Firebase.firestore.collection("notes").document(id)
.delete()
.await()
}查询集合
通过串联筛选条件来构建查询:whereEqualTo、whereGreaterThan、orderBy、limit 等。
查询会返回一个 QuerySnapshot;遍历其中的文档,将每个文档映射为您的模型。
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.tasks.await
suspend fun pendingNotes(): List<Note> {
val snap = Firebase.firestore.collection("notes")
.whereEqualTo("done", false)
.orderBy("createdAt")
.limit(20)
.get()
.await()
return snap.documents.mapNotNull { it.toObject(Note::class.java) }
}实时监听器
Firestore 的强大之处在于实时性。addSnapshotListener 会立即提供当前数据,之后自动推送每一次变化。
它会返回一个 ListenerRegistration — 完成后调用 remove(),停止接收更新。
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
val registration = Firebase.firestore.collection("notes")
.whereEqualTo("done", false)
.addSnapshotListener { snapshot, error ->
if (error != null || snapshot == null) return@addSnapshotListener
val notes = snapshot.toObjects(Note::class.java)
println("Now have ${notes.size} pending notes")
}
// Later: registration.remove()将实时数据转换为 Flow
在 Compose 中,将 Firestore 公开为 Kotlin Flow 是惯用做法。callbackFlow 会将监听器回调桥接为流,而 awaitClose 会在停止收集时移除监听器。
import com.google.firebase.Firebase
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
fun notesFlow(): Flow<List<Note>> = callbackFlow {
val reg = Firebase.firestore.collection("notes")
.addSnapshotListener { snap, err ->
if (err == null && snap != null) {
trySend(snap.toObjects(Note::class.java))
}
}
awaitClose { reg.remove() }
}在 Compose 中显示数据
使用 collectAsStateWithLifecycle() 收集流,并在 LazyColumn 中渲染它。每当 Firestore 发生变化时,列表都会自动更新 — 无需手动刷新。
@Composable
fun NotesScreen(viewModel: NotesViewModel) {
val notes by viewModel.notes.collectAsStateWithLifecycle()
LazyColumn {
items(notes) { note ->
ListItem(
headlineContent = { Text(note.title) },
supportingContent = { Text(note.body) }
)
}
}
}安全规则很重要
默认情况下,Firestore 处于锁定状态。安全规则决定谁可以读取或写入每个路径 — 规则在服务器上运行,客户端无法绕过。
一种常见规则是:用户只能访问以其身份验证 uid 为键的自身数据。
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{document=**} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}快速检查
您希望 Compose 列表在底层 Firestore 数据发生变化时立即更新,而无需手动刷新。应使用哪个 API?
回顾:Firestore
现在,您已经可以使用 Cloud Firestore 存储和同步数据:
- 数据以文档形式存储在集合中;使用 Kotlin 数据类为其建模。
- 使用
add/set写入,使用get读取,使用update/delete修改。 - 使用
whereEqualTo、orderBy、limit进行查询。 - 使用
addSnapshotListener(或callbackFlow)为界面提供实时数据。 - 使用以
request.auth.uid为依据的安全规则保护数据。
下一步:即使应用已关闭,也能通过 Cloud Messaging 联系用户。
常见问题解答
「Cloud Firestore 基础」课时是免费的吗?
是的 — 「Cloud Firestore 基础」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Android Academy 课程的其余内容,请升级到 CoddyKit PRO。 Android Academy 课程共包含 4 节课。
「Cloud Firestore 基础」这节课中我会学到什么?
读取和写入实时数据 你通过在浏览器中直接运行的动手代码来练习 Android Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Android Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Android Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「Cloud Firestore 基础」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Android Academy 课中编写并运行代码吗?
能。每节 Android Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 设置 Firebase
- Firebase 身份验证
- Cloud Firestore 基础
- 使用 Cloud Messaging 推送