Android 中 Flow 的一次性操作

Cod*_*Lee 3 android android-lifecycle kotlin-flow

我正在尝试在 中显示用户信息DetailActivity。因此,我请求数据并从服务器获取用户的数据。但在本例中,返回类型是Flow<User>. 让我向您展示以下代码。

ServiceApi.kt

@GET("endpoint")
suspend fun getUser(@Query("id") id: Int): Response<User>
Run Code Online (Sandbox Code Playgroud)

存储库.kt

fun getUser(id: Int): Flow<User> = flow<User> {
    val userResponse = api.getUser(id = id)
    if (userResponse.isSuccessful) {
        val user = userResponse.body()
        emit(user)
    }
}
.flowOn(Dispatchers.IO)
.catch { // send error }
Run Code Online (Sandbox Code Playgroud)

详细视图模型.kt

class DetailViewModel(
    private val repository : Repository
) {
    val uiState: StateFlow<User> = repository.getUser(id = 369).stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = User() // empty user
    )
}
Run Code Online (Sandbox Code Playgroud)

详细活动.kt

class DetailActivity: AppCompatActivity() {
    ....
    initObersevers() {
        lifecycleScope.launch {
            // i used the `flowWithLifecycle` because the data is just a single object.
            viewModel.uiState.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED).collect { state ->
              // show data
            }
        }
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是,突然间,我意识到这个过程是公正的an one-shot operation,并认为我可以使用suspend函数并User返回Repository.kt.

所以,我改变了Repository.kt

存储库.kt(已更改)

suspend fun getUser(id: Int): User {
    val userResponse = api.getUser(id = id)
    return if(userResponse.isSuccessful) {
        response.body()
    } else {
        User() // empty user
    }
}
Run Code Online (Sandbox Code Playgroud)

在 中DetailViewModel,我想将 转换UserStateFlow<User>因为观察 fromDetailActivity并且我将像以前一样通过使用 来使用它flowWithLifecycle

这个概念是......我认为这只是一个数据,我不需要Flow在存储库中使用。因为它不是像这样的几个项目List

这种方式正确还是错误??

Pin*_*Pie 7

是的,这种一次性流没有任何意义——它只发射一次,仅此而已。

你有两种不同的方法。首先 - 在您的存储库中创建一个状态流,并在每次执行 GET 请求时发出任何值。该流程将暴露于用例和虚拟机级别。我想说这会导致更困难的错误处理(我不喜欢这种方式,但这些事情总是有争议的,哈哈),但它也有一些优点,比如缓存,你总是可以显示/获取以前的结果。

第二种方法是将您的请求保留为一个简单的挂起函数,该函数发送请求,将其结果返回到您的虚拟机(为了简单起见,这里跳过错误处理):

val userFlow: Flow<User>
    get() = _userFlow

private val _userFlow = MutableStateFlow(User())

fun getUser() = launch(viewModelScope) {
    _userFlow.value = repository.getUser()
}
Run Code Online (Sandbox Code Playgroud)

这种实现不会提供任何超出该虚拟机生命周期范围的缓存,但它很容易测试和使用。因此,并不是只有一种“最酷的方法”,而是一个问题,哪种方法更适合您的需求。