I'm developing a fitness app and I use a wrapper around some data classes that contains information shared by all the screens , like info for the current user , what settings are used by the app etc., My initial idea was to retrieve this information from storage every time the screen is presented to the user. I decided to create a class AppStateManager
that contains a SharedFlow
with the app state , and each viewModel would collect that state , this would help when the user will make some changes to the settings because the viewModels would collect the most up to date version.My questions are there any way to make it lifecycle aware and also if there is a cleaner alternative to this ?
This is how I trigger the retrieval of the app state
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
userUid = intent.getStringExtra("USER_UID") ?: guestProfile.uid
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
appStateManager.initAppState(userUid , lifecycleScope.coroutineContext)
}
}
setContent {
WorkoutCompanionTheme {
val databaseScreenViewModel = hiltViewModel<DatabaseScreenViewModel>().apply {
this.beginListeningToAppStateChanges()
}
val profileViewModel = hiltViewModel<ProfileViewModel>().apply {
this.beginListeningToAppStateChanges()
}
val trainingProgramViewModel = hiltViewModel<TrainingProgramViewModel>().apply {
this.beginListeningToAppStateChanges()
}
val homeViewModel = hiltViewModel<HomeViewModel>().apply {
this.beginListeningToAppStateChanges()
}
MainNavigation.MainNavigation(
databaseScreenViewModel = databaseScreenViewModel,
profileViewModel = profileViewModel,
trainingProgramViewModel = trainingProgramViewModel,
homeViewModel= homeViewModel,
startOnBoardFlow = {
startEntryActivity()
}
)
}
}
}
this is the Manager Class
class AppStateManager @Inject constructor(private val workoutRepository : WorkoutRepository ,
@Testing
private val profileRepository : ProfileRepository ,) {
private val _appState = MutableSharedFlow<WorkoutCompanionAppState>(replay = 1 , extraBufferCapacity = 0 , onBufferOverflow = BufferOverflow.SUSPEND )
val appState = _appState.onEach { Log.d("Test" ,it.toString()) }
fun initAppState(userUid : String ,context : CoroutineContext){
CoroutineScope(context = context).launch{
val state = getAppState(userUid) / /function to build from storage the app state , i didn't include the code but is inside the app stateManager
if(state == null){
Log.d("Test" , "Failed to retrieve App State")
}
state?.let {
Log.d("Test" , "Emission from manager")
_appState.emit(it)
Log.d("Test" , "app state listeners = ${_appState.subscriptionCount.value}")
}
}.invokeOnCompletion {
Log.d("Test" , "Init Completed")
}
}
fun updateAppState(appState : WorkoutCompanionAppState,context : CoroutineContext){
Log.d("Test" , "Update called")
CoroutineScope(context).launch {
_appState.emit(appState)
}.invokeOnCompletion {
Log.d("Test" , "update Completed")
}
}
}
this is the function called by the viewModels
fun beginListeningToAppStateChanges() {
viewModelScope.launch{
appStateManager.appState.collectLatest{
_appState.update { it }
}
}
}