Home > OS >  When I change ViewModel var, Composable Doesn't Update in Kotlin Compose
When I change ViewModel var, Composable Doesn't Update in Kotlin Compose

Time:07-26

When I change ViewModel variable, Composable Doesn't Update the View and I'm not sure what to do.

This is my MainActivity:

class MainActivity : ComponentActivity() {
    companion object  {
        val TAG: String = MainActivity::class.java.simpleName
    }

    private val auth by lazy {
        Firebase.auth
    }

    var isAuthorised: MutableState<Boolean> = mutableStateOf(FirebaseAuth.getInstance().currentUser != null)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val user = FirebaseAuth.getInstance().currentUser

        setContent {
            HeroTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    if (user != null) {
                        Menu(user)
                    } else {
                        AuthTools(auth, isAuthorised)
                    }
                }
            }
        }
    }
}

I have a a View Model:

class ProfileViewModel: ViewModel() {
    val firestore = FirebaseFirestore.getInstance()
    var profile: Profile? = null
    val user = Firebase.auth.currentUser

    init {
        fetchProfile()
    }

    fun fetchProfile() {
        GlobalScope.async {
            getProfile()
        }
    }

    suspend fun getProfile() {
        user?.let {
            val docRef = firestore.collection("Profiles")
                .document(user.uid)

            return suspendCoroutine { continuation ->
                docRef.get()
                    .addOnSuccessListener { document ->
                        if (document != null) {
                            this.profile = getProfileFromDoc(document)
                        }
                    }
                    .addOnFailureListener { exception ->
                        continuation.resumeWithException(exception)
                    }
            }
        }
    }
}

And a Composable View upon user autentication:

@Composable
fun Menu(user: FirebaseUser) {
    val context = LocalContext.current
    val ProfileVModel = ProfileViewModel()

    Column(
        modifier = Modifier
            .background(color = Color.White)
            .fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,

        ) {

        Text("Signed in!");


        ProfileVModel.profile?.let {
            Text(it.username);
        }

        Row(
            horizontalArrangement =  Arrangement.Center,
            modifier = Modifier.fillMaxWidth()
        ) {
            TextButton(onClick = {
                FirebaseAuth.getInstance().signOut()
                context.startActivity(Intent(context, MainActivity::class.java))
            }) {
                Text(
                    color = Color.Black,
                    text = "Sign out?",
                    modifier = Modifier.padding(all = 8.dp)
                )
            }
        }
    }
}

When my Firestore method returns, I update the profile var, and "expect" it to be updated in the composable, here:

    ProfileVModel.profile?.let {
        Text(it.username);
    }

However, nothing is changing?

When I was adding firebase functions from inside composable, I could just do:

context.startActivity(Intent(context, MainActivity::class.java))

And it would update the view. However, I'm not quite sure how to do this from inside a ViewModel, since "context" is a Composable-specific feature?

I've tried to look up Live Data, but every tutorial is either too confusing or differs from my code. I'm coming from SwiftUI MVVM so when I update something in a ViewModel, any view that's using the value updates. It doesn't seem to be the case here, any help is appreciated.

Thank you.

CodePudding user response:

Profile in view model should be State<*>

private val _viewState: MutableState<Profile?> = mutableStateOf(null)
val viewState: State<Profile?> = _viewState

In composable

ProfileVModel.profile.value?.let {
   Text(it.username);
}

CodePudding user response:

I recommend using MutableStateFlow.

a simple sample is described in this Medium article :

https://farhan-tanvir.medium.com/stateflow-with-jetpack-compose-7d9c9711c286

  • Related