最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Why is initialValue needed in collectAsStateWithLifecycle for StateFlow? - Stack Overflow

programmeradmin0浏览0评论

I have a ViewModel that exposes a StateFlow representing the UI state of a book list:

class BooksViewModel(private val getBooksUseCase: GetBooksUseCase) : ViewModel() {

    val booksState: Flow<BooksUiState> = flow {
        val result = getBooksUseCase()
        result.onSuccess {
            emit(BooksUiState.Success(it))
        }.onFailure {
            emit(BooksUiState.Error(it))
        }
    }.onStart {
        emit(BooksUiState.Loading(true))
    }.onCompletion {
        emit(BooksUiState.Loading(false))
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = BooksUiState.Loading(true),
    )
}

In my @Composable, I collect this state using collectAsStateWithLifecycle:

@Composable
fun BookScreen(
    onBackPressed: () -> Unit,
    viewModel: BooksViewModel = koinViewModel()
) {
    val uiState by viewModel.booksState.collectAsStateWithLifecycle(
        initialValue = BooksUiState.Loading(true)
    )

    BackHandler(onBack = onBackPressed)

    BookContent()
}

Since booksState is already a StateFlow with an initial value (BooksUiState.Loading(true)), why do we need to pass initialValue to collectAsStateWithLifecycle again?

Is there a way to avoid this redundancy while ensuring correct state collection in Compose?

I have a ViewModel that exposes a StateFlow representing the UI state of a book list:

class BooksViewModel(private val getBooksUseCase: GetBooksUseCase) : ViewModel() {

    val booksState: Flow<BooksUiState> = flow {
        val result = getBooksUseCase()
        result.onSuccess {
            emit(BooksUiState.Success(it))
        }.onFailure {
            emit(BooksUiState.Error(it))
        }
    }.onStart {
        emit(BooksUiState.Loading(true))
    }.onCompletion {
        emit(BooksUiState.Loading(false))
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = BooksUiState.Loading(true),
    )
}

In my @Composable, I collect this state using collectAsStateWithLifecycle:

@Composable
fun BookScreen(
    onBackPressed: () -> Unit,
    viewModel: BooksViewModel = koinViewModel()
) {
    val uiState by viewModel.booksState.collectAsStateWithLifecycle(
        initialValue = BooksUiState.Loading(true)
    )

    BackHandler(onBack = onBackPressed)

    BookContent()
}

Since booksState is already a StateFlow with an initial value (BooksUiState.Loading(true)), why do we need to pass initialValue to collectAsStateWithLifecycle again?

Is there a way to avoid this redundancy while ensuring correct state collection in Compose?

Share Improve this question asked Mar 11 at 19:51 Vivek ModiVivek Modi 7,48320 gold badges103 silver badges232 bronze badges 1
  • 1 There is one that does not need it developer.android/reference/kotlin/androidx/lifecycle/… – tyczj Commented Mar 11 at 20:18
Add a comment  | 

1 Answer 1

Reset to default 8

You declared booksState to be a Flow<BooksUiState>, although the actual object is a StateFlow<BooksUiState>. collectAsStateWithLifecycle() only sees a regular Flow and that usually has no initial value, so it forces you to provide one.

Just properly declare booksState as

val booksState: StateFlow<BooksUiState>

Then collectAsStateWithLifecycle() doesn't need an initial value any more.

发布评论

评论列表(0)

  1. 暂无评论