Search code examples
stateandroid-jetpack-composeandroid-livedatanullableandroid-viewmodel

Migrate to ObserveAsState in Jetpack Compose - null


I am a beginner trying to learn Kotlin by changing an old tutorial to Compose.

I have a ViewModel with


private val _registerStatus = MutableLiveData<Resource<String>>()
    val registerStatus: LiveData<Resource<String>> = _registerStatus

    fun register(email: String, password: String, repeatedPassword: String) {
        _registerStatus.postValue(Resource.loading(null))
        if(email.isEmpty() || password.isEmpty() || repeatedPassword.isEmpty()) {
            _registerStatus.postValue(Resource.error("Please fill out all the fields", null))
            return
        }
        if(password != repeatedPassword) {
            _registerStatus.postValue(Resource.error("The passwords do not match", null))
            return
        }
        viewModelScope.launch {
            val result = repository.register(email, password)
            _registerStatus.postValue(result)
        }
    }

and Fragment with:

 viewModel.registerStatus.observe(viewLifecycleOwner, Observer { result ->
        result?.let {
            when(result.status) {
                Status.SUCCESS -> {
                    registerProgressBar.visibility = View.GONE
                    showSnackbar(result.data ?: "Successfully registered an account")
                }
                Status.ERROR -> {
                    registerProgressBar.visibility = View.GONE
                    showSnackbar(result.message ?: "An unknown error occurred")
                }
                Status.LOADING -> {
                    registerProgressBar.visibility = View.VISIBLE
                }
            }
        }
    })

How could I adapt this code to use Jetpack Compose?

I understand I need to use "ObserveAsState" in a Composable :

registerViewModel.registerStatus.observeAsState()

Truth is, I think I don't really understand the nullable issue, or what val result is doing, or what result -> result?.let is doing, except being some way to pass a non-null value in? If removed, I must make registerStatus.status non-null or safe. So I can do the below:

@Composable
fun subscribeToObservers() {
  val registerStatus by registerViewModel.registerStatus.observeAsState()
when(registerStatus!!.status){
            Status.SUCCESS -> {

            }
            Status.ERROR -> {

            }
            Status.LOADING -> {

            }
         }
    }

, or do I need to get the "result" value over?

Anything to help me toward understanding the issues better would be really appreciated.


Solution

  • You should avoid using !! as that means you know that that variable is never null. Your application is going to crash if the variable is ever null when going through this piece of code.

    I want also to note that logically, you might not be able to find a scenario in which your variable is going to be null so you might get tempted to use !! but it is better to avoid it just in case.

    Using nullableVariable?.let { -> nonNullVariable } is much safer as it only runs if the variable is not null. Unlike !!, it won't cause a crash if the variable is null.

    I would write the code like this:

        @Composable
        fun subscribeToObservers() {
            val registerStatus by registerViewModel.registerStatus.observeAsState()
            registerStatus?.let { nonNullRegisterStatus ->
                when(nonNullRegisterStatus) {
                    Status.SUCCESS -> {}
                    Status.ERROR -> {}
                    Status.LOADING -> {}
                }
            }
        }