I have a interface called TimeZoneMonitor
to monitorize Time Zone or Date changes.
I also have a UseCase that queries the database, looking for information based on the current system date.
The code works as expected in terms of querying based on the given date, but I am unable to update the information when the date or time zone changes.
Code:
TimeZoneMonitor
interface TimeZoneMonitor {
val currentTimeZone: Flow<TimeZone>
val currentDate:Flow<LocalDateTime>
}
TimeZoneBroadcastMonitor
@Singleton
class TimeZoneBroadcastMonitor @Inject constructor(
@ApplicationContext private val context: Context,
@ApplicationScope appScope: CoroutineScope,
@Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher,
) : TimeZoneMonitor {
override val currentTimeZone: SharedFlow<TimeZone> =
callbackFlow {
// Send the default time zone first.
trySend(TimeZone.currentSystemDefault())
// Registers BroadcastReceiver for the TimeZone changes
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_TIMEZONE_CHANGED) return
val zoneIdFromIntent = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
null
} else {
// Starting Android R we also get the new TimeZone.
intent.getStringExtra(Intent.EXTRA_TIMEZONE)?.let { timeZoneId ->
// We need to convert it from java.util.Timezone to java.time.ZoneId
val zoneId = ZoneId.of(timeZoneId, ZoneId.SHORT_IDS)
// Convert to kotlinx.datetime.TimeZone
zoneId.toKotlinTimeZone()
}
}
// If there isn't a zoneId in the intent, fallback to the systemDefault, which should also reflect the change
trySend(zoneIdFromIntent ?: TimeZone.currentSystemDefault())
}
}
trace("TimeZoneBroadcastReceiver.register") {
context.registerReceiver(receiver, IntentFilter(Intent.ACTION_TIMEZONE_CHANGED))
}
// Send here again, because registering the Broadcast Receiver can take up to several milliseconds.
// This way, we can reduce the likelihood that a TZ change wouldn't be caught with the Broadcast Receiver.
trySend(TimeZone.currentSystemDefault())
awaitClose {
context.unregisterReceiver(receiver)
}
}
// We use to prevent multiple emissions of the same type, because we use trySend multiple times.
.distinctUntilChanged()
.conflate()
.flowOn(ioDispatcher)
// Sharing the callback to prevent multiple BroadcastReceivers being registered
.shareIn(appScope, SharingStarted.WhileSubscribed(5_000), 1)
}
GetHomeUseCase
class GetHomeUseCase @Inject constructor(
private val universalisRepository: UniversalisRepository,
private val userDataRepository: UserDataRepository,
) {
operator fun invoke(
date: Int,
): Flow<HomeResource> {
return combine(
userDataRepository.userData,
universalisRepository.countUniversalis(UniversalisResourceQuery(date)),
) { userData, count ->
if (count == 0 && date.isDateValid()) {
universalisRepository.insertFromRemote(UniversalisResourceQuery(date))
}
val newData = universalisRepository.getUniversalisForTest(date).first()
HomeResource(
date = date,
data = newData,
count = count,
dynamic = userData
)
}
}
}
HomeViewModel
@HiltViewModel
class HomeViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val analyticsHelper: AnalyticsHelper,
timeZoneMonitor:TimeZoneMonitor,
val userDataRepository: UserDataRepository,
getHomeUseCase: GetHomeUseCase,
) : ViewModel() {
private val selectedTopicIdKey = "selectedTopicIdKey"
private val route: UniversalisRoute = savedStateHandle.toRoute()
private val selectedTopicId = savedStateHandle.getStateFlow(
key = selectedTopicIdKey,
initialValue = route.initialTopicId.toString(),
)
val currentTimeZone = timeZoneMonitor.currentTimeZone
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
TimeZone.currentSystemDefault(),
)
val zi = ZoneId.of(currentTimeZone.value.id)
val time = ZonedDateTime.now(zi)
private val newDate=time.format(DateTimeFormatter.ofPattern("yyyyMMdd")).toInt()
private var selectedDate = savedStateHandle.getStateFlow(
key = "date",
initialValue = newDate,
)
val uiState: StateFlow<HomeUiState> = combine(
selectedTopicId,
selectedDate,
getHomeUseCase.invoke(
date = selectedDate.value,
),
HomeUiState::HomeData,
).catch<HomeUiState> {
val error = HomeUiState.HomeError(
date = selectedDate.value,
message = it.message!!
)
analyticsHelper.logHomeErrorEvent(error)
emit(error)
}//.distinctUntilChanged()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = HomeUiState.Loading,
)
}
sealed interface HomeUiState {
data object Loading : HomeUiState
data class HomeData(
val selectedTopicId: String?,
val selectedDate:Int,
val topics: HomeResource,
) : HomeUiState
data class HomeError(
val date: Int,
val message: String
) : HomeUiState {
override fun toString(): String {
return "Date: $date Msg: $message"
}
}
data object Empty : HomeUiState
}
HomeScreen
(Jetpack Compose)
@ExperimentalLayoutApi
@Composable
fun HomeScreen(
uiState: HomeUiState,
modifier: Modifier,
onTopicClick: (String) -> Unit,
currentTimeZone: State<TimeZone>,
currentDate: State<LocalDateTime>,
) {
when (uiState) {
HomeUiState.Empty -> EmptyState(modifier = modifier)
is HomeUiState.HomeData -> {
HomeItems(uiState = uiState, onTopicClick = onTopicClick, currentTimeZone=currentTimeZone,currentDate=currentDate,modifier = modifier, haveDate=true)
}
HomeUiState.Loading -> LoadingState(modifier = modifier)
is HomeUiState.HomeError -> {
HomeItems(uiState = uiState, onTopicClick = onTopicClick, currentTimeZone=currentTimeZone,currentDate=currentDate,modifier = modifier, haveDate=false)
}
}
}
@ExperimentalLayoutApi
@Composable
fun HomeItems(
uiState: HomeUiState,
onTopicClick: (String) -> Unit,
modifier: Modifier,
haveDate: Boolean = false,
currentTimeZone: State<TimeZone>,
currentDate: State<LocalDateTime>
) {
// ...
val data = uiState as HomeUiState.HomeData
Text(
text = data.topics.data.fecha,
modifier = Modifier.padding(2.dp),
textAlign = TextAlign.Center,
)
}
My problem with this code is that if I change the date in the system, the HomeData
information is not updated with the new date.
How can I call the UseCase again with the new date and update the UI?
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745075594a4609815.html
评论列表(0条)