Reputation: 163
In parallel, I download data from a local source and check for updates on the server. But for some reason, the sheet data is not updated. I use Firestore.
Fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
checkUpdate()
getData()
}
private fun checkUpdate() {
viewModel.checkUpdate().observe(viewLifecycleOwner, Observer { result ->
when(result) {
is Response.Loading -> { loading() }
is Response.Success -> {
viewModel.updateData()
}
is Response.Error -> { error(result.exception) }
}
})
}
private fun getData() {
viewModel.getData().observe(viewLifecycleOwner, Observer { result ->
when(result) {
is Response.Loading -> { loading() }
is Response.Success -> { success(result.data) }
is Response.Error -> { error(result.exception) }
}
})
}
ViewModel
private var data: LiveData<Response<List<Rule>>>
init {
data = loadData()
}
fun getData() = data
fun updateData() { data = loadData() }
private fun loadData() =
liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
emit(Response.Loading)
val result = repository.getData()
if (result is Response.Success || result is Response.Error) emit(result)
}
fun checkUpdate() =
liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
val lastUpdateTimestamp = Timestamp(
preferences.getLong("PREF_RULE_LAST_UPDATE", 0),
0
)
emit(Response.Loading)
when(val result = repository.checkUpdate(lastUpdateTimestamp)) {
is Response.Success -> {
if (result.data > lastUpdateTimestamp) {
try {
val editor = preferences.edit()
editor.putLong("PREF_RULE_LAST_UPDATE", result.data.seconds)
editor.apply()
emit(Response.Success(true))
} catch (exception: Exception) {
emit(Response.Error(exception))
}
} else {
emit(Response.Success(false))
}
}
is Response.Error -> { emit(result) }
}
}
Repository
suspend fun getData(): Response<List<Rule>> =
suspendCoroutine { continuation ->
firebaseFirestore
.collection(COLLECTION_NAME)
.whereEqualTo("published", true)
.orderBy("number", Query.Direction.ASCENDING)
.get(Source.CACHE)
.addOnSuccessListener { query ->
try {
val data = arrayListOf<Rule>()
query.documents.forEach {document ->
document.toObject(RuleDomain::class.java)?.let {
it.id = document.id
data.add(it.toRule())
}
}
continuation.resume(Response.Success(data))
} catch (exception: Exception) {
Log.e(TAG, exception.localizedMessage!!)
continuation.resume(Response.Error(exception))
}
}
.addOnFailureListener { exception ->
Log.e(TAG, exception.localizedMessage!!)
continuation.resume(Response.Error(exception))
}
}
suspend fun checkUpdate(lastUpdateTimestamp: Timestamp): Response<Timestamp> =
suspendCoroutine { continuation ->
firebaseFirestore
.collection(COLLECTION_NAME)
.whereGreaterThan("update_timestamp", lastUpdateTimestamp)
.orderBy("update_timestamp", Query.Direction.ASCENDING)
.get(Source.SERVER)
.addOnSuccessListener { query ->
try {
val data = query.documents.first()["update_timestamp"] as Timestamp
continuation.resume(Response.Success(data))
} catch (exception: Exception) {
Log.e(TAG, exception.localizedMessage!!)
continuation.resume(Response.Error(exception))
}
}
.addOnFailureListener { exception ->
Log.e(TAG, exception.localizedMessage!!)
continuation.resume(Response.Error(exception))
}
}
I want to replace that the "data" variable is actually being updated since the data appears when the screen is rotated. As far as I know from the documentation viewModel.getData().observe(viewLifecycleOwner, Observer { ... })
should be signed while the fragment is alive, and should commit all changes.
Upvotes: 0
Views: 99
Reputation: 163
I decided to completely abandon part of the code and rewrite it a bit.
Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
getData()
}
private fun getData() {
viewModel.data.observe(viewLifecycleOwner, Observer { result ->
when(result) {
is Response.Loading -> { loading() }
is Response.Success -> { success(result.data) }
is Response.Error -> { error(result.exception) }
}
})
}
ViewModel
private var _data: LiveData<Response<List<Rule>>>
val data: LiveData<Response<List<Rule>>>
get() = _data
init {
_data = loadData()
}
private fun loadData(): LiveData<Response<List<Rule>>> =
liveData(viewModelScope.coroutineContext + Dispatchers.IO) {
emit(Response.Loading)
val lastUpdateTimestamp = Timestamp(preferences.getLong("PREF_RULE_LAST_UPDATE", 0), 0)
val response = repository.getData(lastUpdateTimestamp)
if (response is Response.Success) {
val result = response.data
if (result.containsKey("LAST_UPDATE_TIMESTAMP"))
if (result["LAST_UPDATE_TIMESTAMP"] as Timestamp > lastUpdateTimestamp)
preferences.put("PREF_RULE_LAST_UPDATE", (result["LAST_UPDATE_TIMESTAMP"] as Timestamp).seconds)
if (result.containsKey("DATA"))
emit(Response.Success(result["DATA"] as List<Rule>))
}
if (response is Response.Error)
emit(response)
}
Repository
suspend fun getData(timestamp: Timestamp): Response<HashMap<String, Any?>> =
suspendCoroutine { continuation ->
firebaseFirestore
.collection(COLLECTION_NAME)
.whereGreaterThan("update_timestamp", timestamp)
.orderBy("update_timestamp", Query.Direction.DESCENDING)
.get(Source.SERVER)
.addOnCompleteListener { queryServer ->
val hashMap = HashMap<String, Any?>()
if (!queryServer.result?.isEmpty!!)
hashMap["LAST_UPDATE_TIMESTAMP"] = queryServer.result!!.first().get("update_timestamp") as Timestamp
firebaseFirestore
.collection(COLLECTION_NAME)
.whereEqualTo("published", true)
.orderBy("number", Query.Direction.ASCENDING)
.get(Source.CACHE)
.addOnSuccessListener { queryCache ->
try {
val data = arrayListOf<Rule>()
queryCache.documents.forEach {document ->
document.toObject(RuleDomain::class.java)?.let {
it.id = document.id
data.add(it.toRule())
}
}
hashMap["DATA"] = data
continuation.resume(Response.Success(hashMap))
} catch (exception: Exception) {
Log.e(TAG, exception.localizedMessage!!)
continuation.resume(Response.Error(exception))
}
}
.addOnFailureListener { exception ->
Log.e(TAG, exception.localizedMessage!!)
continuation.resume(Response.Error(exception))
}
}
}
Upvotes: 1