Jetpack Compose: State and LiveData

November 2, 2021

NOTE:

  • State in a value in or pass to composable, where changes of the value would update the UI
  • We store state in ViewModel, and pass it into composable, in order to make the composable stateless and easier to test
  • Using MutableState is the most convinient, but we could use LiveData, Flow or RxJava2

MutableState

ViewModel

class MainViewModel : ViewModel() {
    var currentUser by mutableStateOf<FirebaseUser?>(null)
        private set

    @JvmName("assignCurrentUser")
    fun setCurrentUser(user: FirebaseUser?) {
        currentUser = user
    }
}

Composable

@Composable
fun UserProfileScreen(viewModel: MainViewModel, onSignIn: () -> Unit, onSignOut: () -> Unit) {
    val currentUser = viewModel.currentUser

    Column(modifier = Modifier.padding(16.dp)) {
        if (currentUser == null) {
            Button(onClick = { onSignIn() }){
                Text(text = "Sign in with Google")
            }
        }
        else {
            Text(text = "Welcome, ${currentUser.displayName}")
            Button(onClick = { onSignOut() } ) {
                Text(text = "Sign out")
            }
        }
    }
}

LiveData

ViewModel

class MainViewModel : ViewModel() {
    private var _currentUser: MutableLiveData<FirebaseUser?> = MutableLiveData(null)
    val currentUser: LiveData<FirebaseUser?> = _currentUser

    fun setCurrentUser(user: FirebaseUser?) {
        _currentUser.value = user
    }
}

Composable

@Composable
fun UserProfileScreen(viewModel: MainViewModel, onSignIn: () -> Unit, onSignOut: () -> Unit) {
    val currentUser: FirebaseUser? by viewModel.currentUser.observeAsState(null)

    Column(modifier = Modifier.padding(16.dp)) {
        if (currentUser == null) {
            Button(onClick = { onSignIn() }){
                Text(text = "Sign in with Google")
            }
        }
        else {
            Text(text = "Welcome, ${currentUser!!.displayName}")
            Button(onClick = { onSignOut() } ) {
                Text(text = "Sign out")
            }
        }
    }
}

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.