I have 5 modules (main, splash, pick location, permissions, preferences).
I want to use the Preferences module in Splash and PickLocation.
This is the flow of my modules: Splash -> PickLocation
When I want to use the DataStore class in the PickLocation module to save new locations, I have a problem:
If I create a new instance of the DataStore class in the Splash module and create another instance of the same class in the PickLocation module DataStore not working, but if i just create an instance in the PickLocation everything is working. how can I use dagger hilt to create one instance and access from all modules?
Preference module DI:
package com.mykuyaclient.preference.di
import android.content.Context
import com.mykuyaclient.preference.datastores.CheckLocationIsSetDataStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
object PreferenceModule {
@Provides
fun provideCheckLocationIsSetDataStore(@ApplicationContext appContext: Context): CheckLocationIsSetDataStore =
CheckLocationIsSetDataStore(appContext)
}
PickLocationScreen codes:
@Composable
fun MapScreen(navigatorViewModel: PickLocationViewModel) {
**val context = LocalContext.current
val dataStore = CheckLocationIsSetDataStore(context = context)**
Surface(color = AppColor.ThemeColor.BACKGROUND) {
val mapView = rememberMapViewWithLifecycle()
Column(Modifier.fillMaxSize()) {
Box(modifier = Modifier.fillMaxSize()) {
MapViewContainer(mapView, navigatorViewModel)
MapPinOverlay()
Column(modifier = Modifier.align(Alignment.BottomCenter)) {
Button(
colors = ButtonDefaults.buttonColors(
backgroundColor = AppColor.brandColor.BLUE_DE_FRANCE,
contentColor = AppColor.neutralColor.DOCTOR
),
onClick = {
navigatorViewModel.apply {
// popBackStack()
navigate(HomeDestination.route())
**viewModelScope.launch {
dataStore.set(
this@apply.location.value
)
}**
}
}) {
Text(
text = stringResource(R.string.confirm_address),
style = AppFont.PoppinsTypography.button
)
}
Spacer(modifier = Modifier.size(16.dp))
}
}
}
}
}
SplashScreen codes:
@OptIn(ExperimentalPermissionsApi::class)
@Composable
private fun SplashView(
modifier: Modifier,
multiplePermissionsState: MultiplePermissionsState,
navigator: SplashViewModel = hiltViewModel()
) {
**val context = LocalContext.current
val dataStore = CheckLocationIsSetDataStore(context = context)**
Box(
modifier = modifier
.fillMaxSize()
.background(color = AppColor.brandColor.BLUE_DE_FRANCE)
.padding(start = 64.dp, end = 64.dp, bottom = 16.dp)
) {
Column(modifier = modifier.align(Alignment.Center)) {
Image(
painter = painterResource(id = R.drawable.mykuyatm),
contentDescription = "mykuya tm image"
)
Image(
painter = painterResource(id = R.drawable.mykuya_powered_by),
contentDescription = "mykuya powered by image"
)
}
Loading(modifier = modifier.align(Alignment.BottomCenter))
FeatureThatRequiresPermission(
multiplePermissionsState = multiplePermissionsState, permissionsState = {
if (it) {
navigator.apply {
viewModelScope.launch {
delay(Constants.SPLASH_DELAY)
**dataStore.get.collect { model ->
model.let {
/* if (model.lat == Constants.IF_LOCATION_LAT_NOT_SET && model.lat == Constants.IF_LOCATION_LNG_NOT_SET) {
navigate(PickLocationDestination.route())
}else{
navigate(HomeDestination.route())
}*/
navigate(PickLocationDestination.route())
}
}**
// popBackStack()
}
}
}
})
}
}
DataStore class codes: (How can i use instance of this class in the all of modules)
class CheckLocationIsSetDataStore @Inject constructor(private val context: Context) :
IDataStore<Location, Location> {
override val get: Flow<Location>
get() = context.dataStore.data.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
Log.e("DataStore Exception: ", exception.toString())
}.map { preferences ->
Location("").let {
it.latitude = preferences[DataStoreKeys.IS_LOCATION_LAT_SET_KEY]
?: Constants.IF_LOCATION_LAT_NOT_SET
it.longitude = preferences[DataStoreKeys.IS_LOCATION_LNG_SET_KEY]
?: Constants.IF_LOCATION_LNG_NOT_SET
it
}
}
override suspend fun set(param: Location?) {
context.dataStore.edit { preferences ->
preferences[DataStoreKeys.IS_LOCATION_LAT_SET_KEY] =
param?.latitude ?: Constants.IF_LOCATION_LAT_NOT_SET
preferences[DataStoreKeys.IS_LOCATION_LNG_SET_KEY] =
param?.longitude ?: Constants.IF_LOCATION_LNG_NOT_SET
}
}
}
CodePudding user response:
Hilt can inject dependencies in view models, so you need to create such a model.
Here is a basic example:
class CheckLocationIsSetDataStore @Inject constructor(
@ApplicationContext val context: Context
) {
fun dataStore() = context.dataStore
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "composePreferences")
}
@HiltViewModel
class DataStoreProviderViewModel @Inject constructor(
private val checkLocationIsSetDataStore: CheckLocationIsSetDataStore,
): ViewModel() {
private val key = booleanPreferencesKey("some_test_key")
val get get() = checkLocationIsSetDataStore.dataStore().data.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
Log.e("DataStore Exception: ", exception.toString())
}.map { preferences ->
preferences[key] ?: false
}
fun set(value: Boolean) {
viewModelScope.launch {
checkLocationIsSetDataStore.dataStore().edit {
it[key] = value
}
}
}
}
@Composable
fun TestScreen(
) {
val viewModel = hiltViewModel<DataStoreProviderViewModel>()
val some by viewModel.get.collectAsState(initial = false)
Switch(checked = some, onCheckedChange = { viewModel.set(it) })
}