我的视图模型在这里没有观察到我发布的新数据,除非我再次初始化它,这是我的视图模型:
@HiltViewModel
class AttendanceViewModel@Inject constructor(
private val attendanceHomeUseCase: AttendanceHomeUseCase,
private val sharedPreferences: SharedPreferences,
) : ViewModel() {
fun sharedUserId(): String {
return sharedPreferences.getString("user_id", "0") ?: "0"
}
fun sharedRoleId(): String {
return sharedPreferences.getString("role_id", "0") ?: "0"
}
fun updateSharedPreference() {
sharedPreferences.edit().putString("role_id", "0").apply()
sharedPreferences.edit().putString("user_id", "0").apply()
sendUiEvent(UiEvent.Navigate(Screen.SplashScreen.route))
}
private val _state = MutableStateFlow(HomeState())
val state: MutableStateFlow<HomeState> = _state
init {
getHome()
}
private fun getHome() {
attendanceHomeUseCase(sharedUserId().toInt()).onEach { result ->
when (result) {
is Resource.Success -> {
_state.value = HomeState(home = result.data)
Log.d("shared+Tag", result.data!!.toString())
}
is Resource.Loading -> {
_state.value = HomeState(isLoading = true)
}
is Resource.Error -> {
_state.value = HomeState(error = result.message ?: "Unexpected error!")
}
}
}.launchIn(viewModelScope)
}
}
以下是HomeState数据类:
data class HomeState (
val isLoading: Boolean = false,
val home: AttendanceHome? = null,
val error: String = ""
)
下面是我的用例,我在调用我的API后将结果发送到Resource类:
class AttendanceHomeUseCase@Inject constructor(
val repository: LeadRepository,
) {
operator fun invoke(
userId: Int
) : Flow<Resource<AttendanceHome?>> = flow {
try {
emit(Resource.Loading())
val attendance = repository.getHome(userId)
emit(Resource.Success(attendance.body()))
} catch (e: HttpException) {
emit((Resource.Error(e.localizedMessage ?: "Unexpected error!")))
} catch (e: IOException) {
emit(Resource.Error(e.localizedMessage ?: "Can't reach server, check internet connection!"))
}
}
}
这是我观察状态的组合:
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun PunchItem(
viewModel: AttendanceViewModel,
context: Context,
rosterId: String,
navController: NavController
) {
val state = viewModel.state.collectAsState().value
val checkInState = viewModel.stateCheck.collectAsState().value
val checkOutState = viewModel.stateCheckOut.collectAsState().value
val currentDateTime = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("d'${getDayOfMonthSuffix(currentDateTime.dayOfMonth)}' MMM")
val formattedDate = currentDateTime.format(formatter)
var time1 by rememberSaveable { mutableStateOf("") }
var time2 by rememberSaveable { mutableStateOf("") }
var time3 by rememberSaveable { mutableStateOf("") }
var isPunchIn by rememberSaveable { mutableStateOf(false) }
var isPunchOut by rememberSaveable { mutableStateOf(false) }
var isWorkingHrs by remember { mutableStateOf(false) }
val currentDate = LocalDate.now()
val formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val formattedDate1 = currentDate.format(formatter1)
Box(
modifier = Modifier
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
.fillMaxWidth()
.clip(RoundedCornerShape(2.dp))
.background(Color(0xFFFFF7F7))
) {
AnimatedVisibility(visible = checkInState.isLoading || checkOutState.isLoading, enter = fadeIn(), exit = fadeOut()) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.TopStart).padding(8.dp).size(12.dp), color = RedBColor, strokeWidth = 2.dp)
}
Row(
modifier = Modifier.padding(top = 16.dp, bottom = 16.dp).fillMaxWidth(1f).align(Alignment.CenterStart),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = formattedDate,
fontSize = 16.sp,
color = BackColor,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.padding(16.dp)
)
state.home?.employee_attendance_roster?.first()?.check_in_time?.let {
Log.d("ROSTER_TAG", "inTime: $it")
PunchIn(text = it)
isPunchIn = true
}
Spacer(modifier = Modifier.width(16.dp))
state.home?.employee_attendance_roster?.first()?.check_out_time?.let {
if (it != "00:00:00") {
Log.d("ROSTER_TAG", "outTime: $it")
PunchOut(text = it)
isWorkingHrs = true
}
}
Spacer(modifier = Modifier.width(16.dp))
state.home?.employee_attendance_roster?.let { rosterList ->
if (rosterList.first().working.trim() != "00:00:00" && rosterList.first().working.trim() != "00:00") {
WorkingHours(text = state.home.employee_attendance_roster.first().working)
isWorkingHrs = true
}
}
Spacer(modifier = Modifier.width(16.dp))
}
AnimatedVisibility(
visible = !isWorkingHrs,
modifier = Modifier.align(Alignment.CenterEnd),
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clickable {
if (!isPunchIn) {
time1 = getPunchInTime()
getLocation(context) {
viewModel.checkIn(
CheckInRequest(
viewModel.sharedUserId(),
rosterId,
it.third,
it.second,
it.first,
"",
"",
"",
"",
"",
"",
context.packageName,
)
)
}
isPunchIn = true
navController.navigate(
if (viewModel.sharedRoleId() == "2") {
Screen.AttendanceScreen.route
} else {
Screen.DashboardScreen.route
}
)
} else {
time2 = getPunchOutTime()
getLocation(context) {
viewModel.checkOut(
CheckOutRequest(
viewModel.sharedUserId(),
rosterId,
it.third,
it.second,
it.first,
"",
"",
"",
"",
"",
"",
context.packageName,
)
)
}
isPunchOut = true
navController.navigate(
if (viewModel.sharedRoleId() == "2") {
Screen.AttendanceScreen.route
} else {
Screen.DashboardScreen.route
}
)
}
}
) {
Text(
text = if (!isPunchIn) "Punch In" else "Punch Out",
fontSize = 12.sp,
color = RedColor,
fontWeight = FontWeight.Normal,
modifier = Modifier
.padding(top = 16.dp, end = 4.dp, bottom = 16.dp, start = 16.dp)
)
Icon(
imageVector = Icons.Outlined.ArrowForward,
contentDescription = "",
tint = RedColor,
modifier = Modifier
.padding(top = 16.dp, end = 16.dp, bottom = 16.dp, start = 0.dp)
.size(16.dp)
)
}
}
}
}
因此,在单击按钮后,我将新数据发布到API,但它没有触发视图模型状态,并且API调用成功,我如何使UI异步更新?
我尝试使用实时数据而不是流,但没有工作,问题是我的视图模型不知道新数据发布到API,所以我如何通知它?
1条答案
按热度按时间aiazj4mn1#
尝试使用hiltViewModel()而不是AttendanceViewModel,如下所示