从 ViewModel 采集 Flow 和直接在 Compose 采集 Flow 应该选哪个
Which one should I choose between collecting Flow from ViewModel or collecting Flow in Compose directly
代码 A 在 ViewModel,
中收集 Flow 并使用 MutableStateFlow
将 Flow 转换为热流,然后在 Compose 中使用 collectAsState()
。
代码B在Compose中收集Flow,直接在Compose中使用collectAsState
代码A和代码B哪个更好?
在我看来,代码A在ViewModel中将一个Flow转换为hot Flow,它会保留内存并浪费资源,这是一个好方法吗?
代码A
@Composable
fun BookListScreen(
viewModel: BookListViewModel,
...
) {
val booksListUiState by viewModel.uiState.collectAsState()
...
}
@HiltViewModel
class BookListViewModel @Inject constructor(
private val bookUseCase: BookUseCase
) : ViewModel() {
private var loadBooksJob: Job? = null
private val _uiState = MutableStateFlow(BookListUiState())
val uiState = _uiState.asStateFlow()
init {
loadBooks()
}
fun loadBooks() {
loadBooksJob?.cancel()
loadBooksJob = viewModelScope.launch {
bookUseCase.listBooks().collect { resultState ->
_uiState.update {
it.copy(bookListState = resultState)
}
}
}
}
...
}
override fun loadBooks(): Flow<ResultState<List<Book>>> {
...
}
代码B
@Composable
fun Greeting(
name: String,
mViewMode:SoundViewModel= viewModel()
) {
Column(
) {
val myResult by mViewMode.listRecord().collectAsState(initial =Result.Error(Exception()) )
..
}
@HiltViewModel
class SoundViewModel @Inject constructor(
private val aSoundMeter: RecordRepository
): ViewModel()
{
fun listRecord(): Flow<Result<List<MRecord>>> {
return aSoundMeter.listRecord()
}
}
@Dao
interface RecordDao {
@Query("SELECT * FROM record_table ORDER BY createdDate desc")
fun listRecord(): Flow<List<RecordEntity>>
}
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
...
}
}
在 代码 A 中,您要保持流向视图模型。因此,该流程将在用户旋转设备的情况下被保存。此外,如果 BookListScreen
.
中的重组,则不会调用 loadBooks
在 代码 B 中,每次发生重组时都会调用 listRecord
,因此每次重绘屏幕时,您都在进行数据库调用。由于您的数据库是本地的,因此损坏看起来并没有那么严重,但是如果您使用的是远程数据库(如 Firebase 或 REST Web 服务),此代码将在每次重组时执行网络调用,包括当您旋转设备或返回时到这个屏幕。
检查一下this Playlist from Android Developers Channel. In particular this video(更侧重于您的问题)。
代码 A 在 ViewModel,
中收集 Flow 并使用 MutableStateFlow
将 Flow 转换为热流,然后在 Compose 中使用 collectAsState()
。
代码B在Compose中收集Flow,直接在Compose中使用collectAsState
代码A和代码B哪个更好?
在我看来,代码A在ViewModel中将一个Flow转换为hot Flow,它会保留内存并浪费资源,这是一个好方法吗?
代码A
@Composable
fun BookListScreen(
viewModel: BookListViewModel,
...
) {
val booksListUiState by viewModel.uiState.collectAsState()
...
}
@HiltViewModel
class BookListViewModel @Inject constructor(
private val bookUseCase: BookUseCase
) : ViewModel() {
private var loadBooksJob: Job? = null
private val _uiState = MutableStateFlow(BookListUiState())
val uiState = _uiState.asStateFlow()
init {
loadBooks()
}
fun loadBooks() {
loadBooksJob?.cancel()
loadBooksJob = viewModelScope.launch {
bookUseCase.listBooks().collect { resultState ->
_uiState.update {
it.copy(bookListState = resultState)
}
}
}
}
...
}
override fun loadBooks(): Flow<ResultState<List<Book>>> {
...
}
代码B
@Composable
fun Greeting(
name: String,
mViewMode:SoundViewModel= viewModel()
) {
Column(
) {
val myResult by mViewMode.listRecord().collectAsState(initial =Result.Error(Exception()) )
..
}
@HiltViewModel
class SoundViewModel @Inject constructor(
private val aSoundMeter: RecordRepository
): ViewModel()
{
fun listRecord(): Flow<Result<List<MRecord>>> {
return aSoundMeter.listRecord()
}
}
@Dao
interface RecordDao {
@Query("SELECT * FROM record_table ORDER BY createdDate desc")
fun listRecord(): Flow<List<RecordEntity>>
}
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override fun listRecord(): Flow<Result<List<MRecord>>> {
...
}
}
在 代码 A 中,您要保持流向视图模型。因此,该流程将在用户旋转设备的情况下被保存。此外,如果 BookListScreen
.
loadBooks
在 代码 B 中,每次发生重组时都会调用 listRecord
,因此每次重绘屏幕时,您都在进行数据库调用。由于您的数据库是本地的,因此损坏看起来并没有那么严重,但是如果您使用的是远程数据库(如 Firebase 或 REST Web 服务),此代码将在每次重组时执行网络调用,包括当您旋转设备或返回时到这个屏幕。
检查一下this Playlist from Android Developers Channel. In particular this video(更侧重于您的问题)。