我试图在当前视图呈现后立即显示一个对话框。但是,该对话框显示了两次(可能是由于重组的工作原理)。
val checkGpsEnabled by viewModel.checkGpsEnabled.collectAsState()
val showGpsDisabledDialog by viewModel.showGpsDisabledDialog.collectAsState()
val locationManager = LocalContext.current.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (checkGpsEnabled) {
val gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
viewModel.setGpsChecked()
if (!gpsEnabled) {
viewModel.openGpsDisabledDialog()
}
}
Log.d(TAG, showGpsDisabledDialog.toString())
if (showGpsDisabledDialog) {
Log.d(TAG, "dialog")
val context = LocalContext.current
TwoActionsDialog(
onDismissRequest = {
Log.d(TAG, "dismiss")
viewModel.closeGpsDisabledDialog()
},
mainText = "Gps disabled",
secondaryText = "Please enable location services.\nOtherwise, the app will not know where you took the photos.",
primaryButtonText = "OK, go to settings",
secondaryButtonText = "No, continue without location",
onPrimaryButtonClick = {
viewModel.closeGpsDisabledDialog()
context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
},
onSecondaryButtonClick = {
Log.d(TAG, "decline")
viewModel.closeGpsDisabledDialog()
}
)
}
视图模型:
@HiltViewModel
class MapViewModel @Inject constructor(): ViewModel() {
private var _checkGpsEnabled: MutableStateFlow<Boolean> = MutableStateFlow(true)
val checkGpsEnabled: StateFlow<Boolean> get() = _checkGpsEnabled.asStateFlow()
private var _showGpsDisabledDialog: MutableStateFlow<Boolean> = MutableStateFlow(false)
val showGpsDisabledDialog: StateFlow<Boolean> get() = _showGpsDisabledDialog.asStateFlow()
fun setGpsChecked() {
if (_checkGpsEnabled.value)
_checkGpsEnabled.value = false
}
fun openGpsDisabledDialog() {
if(!_showGpsDisabledDialog.value)
_showGpsDisabledDialog.value = true
}
fun closeGpsDisabledDialog() {
if(_showGpsDisabledDialog.value)
_showGpsDisabledDialog.value = false
}
}
我尝试将状态存储在可组合项中,然后存储在视图模型中。 我尝试使用 LaunchedEffect 设置这些标志(因此它们在可组合渲染之前不是 true) 我尝试使用延迟在视图模型中将它们设置为 true。
我发现在所有这些情况下,通过渲染一个带有文本的简单对话框,对话框会显示两次,并注意到有两个文本重叠
你的代码非常复杂,很难理解。从上面的代码来看,我认为如果设备的 GPS 被禁用,您想显示一个对话框。
这是我的简单且可重复使用的方法:
上下文扩展:您可以编写以下扩展函数(最好将其放在项目中 utils 包下的单独文件中)。它返回一个回调流,流式传输 GPS 设置中的实时变化。
fun Context.observeGpsStatus(): Flow<Boolean> = callbackFlow {
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
val isGpsEnabled = {
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
}
// Emit initial status
trySend(isGpsEnabled())
val gpsStatusReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
trySend(isGpsEnabled())
}
}
val filter = IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION)
registerReceiver(gpsStatusReceiver, filter)
awaitClose {
unregisterReceiver(gpsStatusReceiver)
}
}
GpsStatusObserver 可组合: 这是一个简单的可重用可组合项,可以集成到任何项目的任何屏幕中。
@Composable
fun GpsStatusObserver() {
val context = LocalContext.current
val gpsFlow = remember { context.observeGpsStatus() }
val isGpsEnabled = gpsFlow.collectAsState(initial = true)
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) {}
if (!isGpsEnabled.value) {
PermissionDialog(
title = stringResource(id = R.string.enable_gps),
permissionTextProvider = GPSPermissionTextProvider(),
isPermanentlyDeclined = true,
onDismiss = { },
onOkClick = { }
) {
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
launcher.launch(intent)
}
}
}
然后只需在屏幕可组合项中调用它即可:
@Composable
fun ExampleScreen() {
GpsStatusObserver()
// other content of the screen
}