如何使用 MVVM 模式从 Firestore 检索数据
How to retrieve data from Firestore with the MVVM pattern
我正在创建一个 android 遵循 MVVM 赞助人的应用程序,目的是从 Firebase 集合中检索数据。
在应用此模式之前,我进行了概念验证,并且能够从 Firebase 集合中检索数据。但是一旦我应用了 MVVM,我就无法从那个集合中获取数据,我的屏幕上什么也没有显示。我无法 return 将存储库中的数据绘制在屏幕上。
这是我的代码:
型号:
data class PotatoesData(
val modifiedDate: String,
var potatoes: List<Potato>
)
data class Potato(
val type: String,
val site: String
)
州:
data class PotatoesState(
val isLoading: Boolean = false,
val potatoes: List<Potato> = emptyList(),
val error: String = ""
)
模型视图:
@HiltViewModel
class PotatoesViewModel @Inject constructor(
private val getPotatoesDataUseCase: GetPotatoesData
) : ViewModel() {
private val _state = mutableStateOf(PotatoesState())
val state: State<PotatoesState> = _state
init {
getPotatoes()
}
private fun getPotatoes() {
getPotatoesDataUseCase().onEach { result ->
when (result) {
is Resource.Success -> {
_state.value = PotatoesState(potatoes = result.data?.potatoes ?: emptyList())
}
is Resource.Error -> {
_state.value = PotatoesState(
error = result.message ?: "An unexpected error occurred"
)
}
is Resource.Loading -> {
_state.value = PotatoesState(isLoading = true)
}
}
}.launchIn(viewModelScope)
}
}
用例:
class GetPotatoesData @Inject constructor(
private val repository: PotatoRepository
) {
operator fun invoke(): Flow<Resource<PotatoesData>> = flow {
try {
emit(Resource.Loading())
val potatoes = repository.getPotatoesData()
emit(Resource.Success(potatoes))
} catch (e: IOException) {
emit(Resource.Error("Couldn't reach server. Check your internet connection."))
}
}
}
存储库实现:
class PotatoRepositoryImpl : PotatoRepository {
override suspend fun getPotatoesData(): PotatoesData {
var potatoes = PotatoesData("TEST", emptyList())
FirestoreProvider.getLastPotatoes(
{ potatoesData ->
if (potatoesData != null) {
potatoes = potatoesData
}
},
{
potatoes
}
)
return potatoes
}
}
Firestore 提供商:
object FirestoreProvider {
private val incidentsRef = FirebaseFirestore.getInstance().collection(FirestoreCollection.POTATOES.key)
fun getLastPotatoes(
success: (potatoesData: PotatoesData?) -> Unit,
failure: () -> Unit
) {
val query: Query = orderBy(FirestoreField.CREATED_DATE, Query.Direction.DESCENDING).limit(1)
val querySnapshot: Task<QuerySnapshot> = query.get()
querySnapshot
.addOnSuccessListener {
if (!querySnapshot.result.isEmpty) {
val document = querySnapshot.result.documents[0]
val potatoesDataDB: PotatoesDataDto? = document.toObject(PotatoesDataDto::class.java)
potatoesDataDB?.let {
success(potatoesDataDB.toPotatoesData())
} ?: run {
success(null)
}
} else {
success(null)
}
}
.addOnFailureListener {
failure()
}
}
private fun orderBy(field: FirestoreField, direction: Query.Direction): Query {
return incidentsRef.orderBy(field.key, direction)
}
}
感谢您提供的任何帮助!提前致谢!
我认为错误在于您处理 Firestore 回调的方式。在 FirestoreProvider
中:回调将在函数 getLastPotatoes
return 之后触发。尝试使该功能挂起并使用 suspendCoroutine
等待回调和 return 结果。它看起来像:
suspend fun getLastPotatoes() = suspendCoroutine <PotatoesData?> { continuation ->
val query: Query = orderBy(FirestoreField.CREATED_DATE, Query.Direction.DESCENDING).limit(1)
val querySnapshot: Task<QuerySnapshot> = query.get()
querySnapshot
.addOnSuccessListener {
if (!querySnapshot.result.isEmpty) {
val document = querySnapshot.result.documents[0]
val potatoesDataDB: PotatoesDataDto? = document.toObject(PotatoesDataDto::class.java)
potatoesDataDB?.let {
continuation.resume(potatoesDataDB.toPotatoesData())
} ?: run {
continuation.resume(null)
}
} else {
continuation.resume(null)
}
}
.addOnFailureListener {
continuation.resumeWithException(...)
}
}
suspendCoroutine
暂停执行它的协程,直到我们决定通过调用适当的方法继续 - Continuation.resume...
.
在你的 PotatoRepositoryImpl
:
override suspend fun getPotatoesData(): PotatoesData {
var potatoes = PotatoesData("TEST", emptyList())
try {
val potatoesData = FirestoreProvider.getLastPotatoes()
if (potatoesData != null) {
potatoes = potatoesData
}
} catch (e: Exception) {
// handle Exception
}
return potatoes
}
我正在创建一个 android 遵循 MVVM 赞助人的应用程序,目的是从 Firebase 集合中检索数据。
在应用此模式之前,我进行了概念验证,并且能够从 Firebase 集合中检索数据。但是一旦我应用了 MVVM,我就无法从那个集合中获取数据,我的屏幕上什么也没有显示。我无法 return 将存储库中的数据绘制在屏幕上。
这是我的代码:
型号:
data class PotatoesData(
val modifiedDate: String,
var potatoes: List<Potato>
)
data class Potato(
val type: String,
val site: String
)
州:
data class PotatoesState(
val isLoading: Boolean = false,
val potatoes: List<Potato> = emptyList(),
val error: String = ""
)
模型视图:
@HiltViewModel
class PotatoesViewModel @Inject constructor(
private val getPotatoesDataUseCase: GetPotatoesData
) : ViewModel() {
private val _state = mutableStateOf(PotatoesState())
val state: State<PotatoesState> = _state
init {
getPotatoes()
}
private fun getPotatoes() {
getPotatoesDataUseCase().onEach { result ->
when (result) {
is Resource.Success -> {
_state.value = PotatoesState(potatoes = result.data?.potatoes ?: emptyList())
}
is Resource.Error -> {
_state.value = PotatoesState(
error = result.message ?: "An unexpected error occurred"
)
}
is Resource.Loading -> {
_state.value = PotatoesState(isLoading = true)
}
}
}.launchIn(viewModelScope)
}
}
用例:
class GetPotatoesData @Inject constructor(
private val repository: PotatoRepository
) {
operator fun invoke(): Flow<Resource<PotatoesData>> = flow {
try {
emit(Resource.Loading())
val potatoes = repository.getPotatoesData()
emit(Resource.Success(potatoes))
} catch (e: IOException) {
emit(Resource.Error("Couldn't reach server. Check your internet connection."))
}
}
}
存储库实现:
class PotatoRepositoryImpl : PotatoRepository {
override suspend fun getPotatoesData(): PotatoesData {
var potatoes = PotatoesData("TEST", emptyList())
FirestoreProvider.getLastPotatoes(
{ potatoesData ->
if (potatoesData != null) {
potatoes = potatoesData
}
},
{
potatoes
}
)
return potatoes
}
}
Firestore 提供商:
object FirestoreProvider {
private val incidentsRef = FirebaseFirestore.getInstance().collection(FirestoreCollection.POTATOES.key)
fun getLastPotatoes(
success: (potatoesData: PotatoesData?) -> Unit,
failure: () -> Unit
) {
val query: Query = orderBy(FirestoreField.CREATED_DATE, Query.Direction.DESCENDING).limit(1)
val querySnapshot: Task<QuerySnapshot> = query.get()
querySnapshot
.addOnSuccessListener {
if (!querySnapshot.result.isEmpty) {
val document = querySnapshot.result.documents[0]
val potatoesDataDB: PotatoesDataDto? = document.toObject(PotatoesDataDto::class.java)
potatoesDataDB?.let {
success(potatoesDataDB.toPotatoesData())
} ?: run {
success(null)
}
} else {
success(null)
}
}
.addOnFailureListener {
failure()
}
}
private fun orderBy(field: FirestoreField, direction: Query.Direction): Query {
return incidentsRef.orderBy(field.key, direction)
}
}
感谢您提供的任何帮助!提前致谢!
我认为错误在于您处理 Firestore 回调的方式。在 FirestoreProvider
中:回调将在函数 getLastPotatoes
return 之后触发。尝试使该功能挂起并使用 suspendCoroutine
等待回调和 return 结果。它看起来像:
suspend fun getLastPotatoes() = suspendCoroutine <PotatoesData?> { continuation ->
val query: Query = orderBy(FirestoreField.CREATED_DATE, Query.Direction.DESCENDING).limit(1)
val querySnapshot: Task<QuerySnapshot> = query.get()
querySnapshot
.addOnSuccessListener {
if (!querySnapshot.result.isEmpty) {
val document = querySnapshot.result.documents[0]
val potatoesDataDB: PotatoesDataDto? = document.toObject(PotatoesDataDto::class.java)
potatoesDataDB?.let {
continuation.resume(potatoesDataDB.toPotatoesData())
} ?: run {
continuation.resume(null)
}
} else {
continuation.resume(null)
}
}
.addOnFailureListener {
continuation.resumeWithException(...)
}
}
suspendCoroutine
暂停执行它的协程,直到我们决定通过调用适当的方法继续 - Continuation.resume...
.
在你的 PotatoRepositoryImpl
:
override suspend fun getPotatoesData(): PotatoesData {
var potatoes = PotatoesData("TEST", emptyList())
try {
val potatoesData = FirestoreProvider.getLastPotatoes()
if (potatoesData != null) {
potatoes = potatoesData
}
} catch (e: Exception) {
// handle Exception
}
return potatoes
}