Возможно, я не понимаю, как на самом деле работает эта временная метка RTDB. На этом скриншоте это именно тот момент, когда было написано. Справа время по ntp-серверу nist.time.gov; в центре находится еще одна страница, показывающая представление времени Unix для справки; слева — пульс, записанный с помощью ServerValue.TIMESTAMP; а ниже приведен журнал, показывающий смещение времени из dbRef.database.getReference(".info/serverTimeOffset").

Эта запись была сделана с использованием реального устройства, а не эмулятора. Ниже приведен скриншот, показывающий, что часы устройства также синхронизированы со временем ntp-сервера.

Код, выполняющий запись:
Код: Выделить всё
@HiltViewModel
class MainViewModel @Inject constructor(
private val prefsStore: PrefsStore,
private val currentUserManager: CurrentUserManager
) : ViewModel() {
/**Current user*/
private var currentUserJob: Job? = null
private var authJob: Job? = null
private val _mainUiState = MutableStateFlow(MainUiState())
val currentUserUiState = _mainUiState.asStateFlow()
private var presencaJob: Job? = null
private var heartbeatJob: Job? = null
init {
listenAuth()
}
fun listenAuth() {
authJob?.cancel()
authJob = viewModelScope.launch {
currentUserManager.listenAuth().onStart {
_mainUiState.update {
MainUiState(
isTimeOut = it.isTimeOut,
isLoading = true
)
}
}.collect { firebaseUser ->
logl(firebaseUser?.uid)
currentUserJob?.cancel()
when {
firebaseUser == null -> _mainUiState.update {
MainUiState(
isTimeOut = it.isTimeOut,
signFlow = SignFlow.NeedLogin
)
}
!firebaseUser.isEmailVerified -> _mainUiState.update {
MainUiState(
isTimeOut = it.isTimeOut,
signFlow = SignFlow.NeedVerifyEmail
)
}
else -> listenCurrentUser(firebaseUser.uid)
}
}
}
}
fun listenCurrentUser(uid: UsuarioUid) {
currentUserJob = viewModelScope.launch {
currentUserManager.listenCurrentUser(uid).catch {
logout()
currentUserJob?.cancel()
logl("listenCurrentUser: catch:${it.message}")
}.collect { usuario ->
logl("listenCurrentUser: user>$usuario")
if (presencaJob?.isActive != true) listenPresenca(usuario.uid)
_mainUiState.update {
MainUiState(
isTimeOut = it.isTimeOut,
currentDrawerItemList = when (usuario.maxProfile) {
Profile.Gestor, Profile.GestorMestre -> if (usuario.empresaMap.isNotEmpty()) gestorDrawerItemList else consumidorDrawerItemList
Profile.Consumidor -> consumidorDrawerItemList
else -> emptyList()
},
signFlow = if (usuario == Usuario()) SignFlow.NeedRegisterDb else SignFlow.None,
usuario = usuario
)
}
}
}
}
fun listenPresenca(uid: DatabaseKey){
presencaJob?.cancel()
presencaJob = viewModelScope.launch {
currentUserManager.listenPresenca(uid = uid).collect {deviceId->
deviceId?.let {
if (heartbeatJob?.isActive != true) startHeartbeat(
uid = uid,
deviceId = deviceId
)
}
}
}
}
fun startHeartbeat(uid: String, deviceId: String) {
heartbeatJob?.cancel()
heartbeatJob = viewModelScope.launch {
while (isActive) {
currentUserManager.updateHeartbeat(uid,deviceId)
delay(30_000L)
}
}
}
override fun onCleared() {
heartbeatJob?.cancel()
super.onCleared()
}
}
override suspend fun updateHeartbeat(
uid: DatabaseKey,
deviceId: String
) {
dbRef.database.getReference(".info/serverTimeOffset").addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(s: DataSnapshot) {
val offset = s.getValue(Long::class.java) ?: 0L
Log.d(TAG, "serverTimeOffset = $offset ms.")
}
override fun onCancelled(e: DatabaseError) {}
})
dbRef.child(Nodes.USUARIOS_PRESENCA).child(uid).child("connections").child(deviceId).setValue(ServerValue.TIMESTAMP).await()
}
Хотелось бы понять:
- Почему RTDB записывает будущую временную метку по отношению к текущему моменту по NTP-серверам?
- Почему такое большое время разница?
- У моего клиента проблемы? Что это может быть?
- Как это исправить, чтобы не было разницы более чем в одну минуту?
Подробнее здесь: https://stackoverflow.com/questions/798 ... -large-off
Мобильная версия