简体   繁体   English

实时数据观察者

[英]LiveData Observer

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.我使用 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.据我从文档中知道viewModel.getData().observe(viewLifecycleOwner, Observer { ... })应该在片段处于活动状态时签名,并且应该提交所有更改。

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))
                        }
                }
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM