'Why do I need invoke collect in Compose UI when I use MutableStateFlow?

I have read the Android official artical.

I see that MutableStateFlow is hot Flow and is observed by Compose to trigger recomposition when they change.

The Code A is from the the Android official artical, it's OK.

I'm very stranger why the author need to invoke collect to get latest value for Compose UI in Code A.

I think the Compose UI can always get the latest value of latestNewsViewModel.uiState, why can't I use Code B do the the same work?

Code A

class LatestNewsActivity : AppCompatActivity() {
    private val latestNewsViewModel = // getViewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
     
        lifecycleScope.launch {          
            repeatOnLifecycle(Lifecycle.State.STARTED) {               
                latestNewsViewModel.uiState.collect { uiState ->                
                    when (uiState) {
                        is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
                        is LatestNewsUiState.Error -> showError(uiState.exception)
                    }
                }
            }
        }
    }
}
    
class LatestNewsViewModel(
    private val newsRepository: NewsRepository
) : ViewModel() {
  
    private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList())) 
    val uiState: StateFlow<LatestNewsUiState> = _uiState
    init {
        viewModelScope.launch {
            newsRepository.favoriteLatestNews            
                .collect { favoriteNews ->
                    _uiState.value = LatestNewsUiState.Success(favoriteNews)
                }
        }
    }
}

Code B

class LatestNewsActivity : ComponentActivity() {
    private val latestNewsViewModel = // getViewModel()
    override fun onCreate(savedInstanceState: Bundle?) {       
        super.onCreate(savedInstanceState)
        setContent {
            SoundMeterTheme {
                Surface(color = MaterialTheme.colors.background) {
                    Greeting(latestNewsViewModel)
                }
            }
        }    
    }
}

@Composable
fun Greeting(latestNewsViewModel: LatestNewsViewModel) {
    val myUIState by remember{ latestNewsViewModel.uiState }

    when (myUIState) {
         is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
         is LatestNewsUiState.Error -> showError(uiState.exception)
    }
}

//The same

Add Content

To RaBaKa 78: Thanks!

By your opinion, can I use Code C instead of Code A?

Code C

class LatestNewsActivity : ComponentActivity() {
    private val latestNewsViewModel = // getViewModel()
    override fun onCreate(savedInstanceState: Bundle?) {       
        super.onCreate(savedInstanceState)
        setContent {
            SoundMeterTheme {
                Surface(color = MaterialTheme.colors.background) {
                    Greeting(latestNewsViewModel)
                }
            }
        }    
    }
}

@Composable
fun Greeting(latestNewsViewModel: LatestNewsViewModel) {
    val myUIState by remember{ latestNewsViewModel.uiState.collectAsState() }

    when (myUIState) {
         is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
         is LatestNewsUiState.Error -> showError(uiState.exception)
    }
}

//The same


Solution 1:[1]

Compose need State not StateFlow to recompose accordingly,

you can easily convert StateFlow to State in compose

val myUiState = latestNewsViewModel.uiState.collectAsState()

There is no need of using a remember {} because your StateFlow is from your viewModel, so it can manage the recomposition without remember

So like CODE B you can manually check the state of the StateFLow or convert to State and automatically recompose when the state changes.

The Code A is XML way of doing things where you can call other functions but in Compose you should do that steps in your viewModel

CODE D

class LatestNewsViewModel(
    private val newsRepository: NewsRepository
) : ViewModel() {


private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList())) 
val uiState: StateFlow<LatestNewsUiState> = _uiState
init {
    viewModelScope.launch {
        newsRepository.favoriteLatestNews            
            .collect { favoriteNews ->
                _uiState.value = LatestNewsUiState.Success(favoriteNews)
            }
      }
   }
}


@Composable
fun Greeting(latestNewsViewModel: LatestNewsViewModel) {
    val myUIState = latestNewsViewModel.uiState.collectAsState()

    Column(modifier = Modifier.fillMaxSIze()) {
         when(myUIState) {
             is LatestNewsUiState.Success -> SuccessComposable(uiState.news)
             is LatestNewsUiState.Error -> showError(uiState.exception) -> ErrorComposable(uiState.exception)
         }
    }

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1