简体   繁体   中英

Access the login state from every screen (Jetpack Compose + MVVM + Hilt)

I try to access the login state and other user information everywhere in my app.

Here is how I plan on doing it:

Create a UserState data class:

data class UserState(
    val username: String = "",
    val profileImageUrl: String = "",
    var isLoggedIn: Boolean = false,
    val isPremiumUser: Boolean = false,
    val coins: Int = 0
)

Make it a singleton with hilt and inject it into my AuthRepository:

    @Provides
    @Singleton
    fun provideUserState() = UserState()

    @Singleton
    @Provides
    fun provideAuthRepository(userState: UserState): AuthRepository {
        return AuthRepositoryImpl(userState)
    }

then when the authentication (firebase + custom backend) is succesfull or other auth functions get called I update the userState with the userData:

class AuthRepositoryImpl @Inject constructor( 
    private var userState: UserState 
) : AuthRepository {

    override fun getUserState(): UserState {
        return userState
    }

    override suspend fun authenticateUser(token: String){
        
        val responseUser = authenticateUser(token)
        if (responseUser != null) {
            userState = UserState(
                username = responseUser.username,
                profileImageUrl = responseUser.profileImageUrl,
                isLoggedIn = true,
                isPremiumUser = responseUser.profileImageUrl,
                coins = responseUser.coins
            )
        } 
    } 
}

Now comes the part where I am not sure on how to do it, how do I observe the userState from my ViewModels? If I call for example the logOut function in my AuthRepository from ViewModel XI want to see/get the change in ViewModel Y.

I call the getUserState method for example in the init block of my MainViewModel:

init {
    _mainUserState.value = authRepository.getUserState()
}

So the problem is it only gets updated on the start, how can I observe changes that get made to the UserState Singleton? I'm not sure if flows are the answer and if yes how exactly to use them int his scenario

You can do something like this with flow in you'r auth repository:

private val _authData = MutableStateFlow<AuthEvent>(AuthEvent.Nothing)
    val authData: Flow<AuthEvent> = _authData

then emit like this when login/logout

_authData.emit(AuthEvent.Login)
  • AuthEvent is just a sealed class

  • Add the AuthState to AuthEvent.Login class

  • you can do shared flow too



then in you'r viewModel observe it under viewModelScope

viewModelScope.launch {
            authRepository.getAuthFlow().collect() { data ->
                when (data) {
                    is AuthEvent.Logout -> {
                        sendUiEvent(MainUIEvent.Logout)
                        _state.value = state.value.copy(isLoggedIn = false, authData = null)
                    }

                    is AuthEvent.Login -> {
                        _state.value = state.value.copy(isLoggedIn = true, authData = data.authData)
                        sendUiEvent(MainUIEvent.LoggedIn)
                    }

                    is AuthEvent.Nothing -> {

                    }
                }
            }
        }

this appoarch allows you to handle auth status and navigation from you mainViewModel

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM