在另一个模块的刀柄中创建 class 的实例
Create instance of a class in the hilt in the another module
我有 5 个模块(主要、启动、选择位置、权限、首选项)。
我想在 Splash 和 PickLocation 中使用 Preferences 模块。
这是我的模块的流程:Splash -> PickLocation
当我想使用 PickLocation 模块中的 DataStore class 来保存新位置时,我遇到了问题:
如果我在 Splash 模块中创建 DataStore class 的新实例并在 PickLocation 模块中创建相同 class 的另一个实例 DataStore 不起作用,但如果我只是创建一个实例在 PickLocation 中一切正常。如何使用匕首柄创建一个实例并从所有模块访问?
偏好模块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 代码:
@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))
}
}
}
}
}
启动画面代码:
@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 代码:(我如何在所有模块中使用此 class 的实例)
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
}
}
}
Hilt 可以在视图模型中注入依赖项,因此您需要创建这样的模型。
这是一个基本示例:
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) })
}
我有 5 个模块(主要、启动、选择位置、权限、首选项)。
我想在 Splash 和 PickLocation 中使用 Preferences 模块。
这是我的模块的流程:Splash -> PickLocation
当我想使用 PickLocation 模块中的 DataStore class 来保存新位置时,我遇到了问题:
如果我在 Splash 模块中创建 DataStore class 的新实例并在 PickLocation 模块中创建相同 class 的另一个实例 DataStore 不起作用,但如果我只是创建一个实例在 PickLocation 中一切正常。如何使用匕首柄创建一个实例并从所有模块访问?
偏好模块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 代码:
@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))
}
}
}
}
}
启动画面代码:
@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 代码:(我如何在所有模块中使用此 class 的实例)
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
}
}
}
Hilt 可以在视图模型中注入依赖项,因此您需要创建这样的模型。
这是一个基本示例:
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) })
}