【问题标题】:FIRESTORE persistent dataFIRESTORE 持久数据
【发布时间】:2017-11-22 12:19:57
【问题描述】:

谈到 firestore 持久数据,假设用户在第一次启动应用程序时没有任何连接。我将一些数据添加到 Firestore 数据库(如 userID..),我可以使用 get() 方法将其取回。现在用户关闭应用程序。

  1. 下次他打开应用程序时(仍然没有连接),他是否能够检索以前存储的数据,就像以 sharedprefs 的方式存储一样? 我无法清楚地弄清楚如何找到一种正确的方法来设置具有持久数据的初始化阶段。

  2. 我有几个片段。每次启动其中一个时,我使用“onResume”方法从数据中填充我的组件(之前存储在 sharedpref 中)。当我设置 Firestore getData 时,需要时间来检索。因此,如果用户从当前片段更改为另一个片段,当连接打开时,我会遇到有关组件为空或在数据库结果完成时无法访问的错误。

    实现这种“onResume”数据重新填充的最佳方式是什么?

更新:

下面是一段代码:MainAvtivity.kt

FirebaseFirestore.getInstance().firestoreSettings.isPersistenceEnabled
        sightingsDatabase = FirebaseFirestore.getInstance()
        docname=FireStoreSetup().setupFB(sightingsDatabase!!,this)

一个 kotlin 对象类来填充我的文档:

data class Sighting(var userID: String,
                    var sig_wit_situation_type: Int,
                    var sig_env_background_type: Int,
                    var sig_ground_type: Int,
                    var sig_YYYY: String,
                    var sig_MM: String,
                    var sig_DD: String,
                    var sig_time_start: String,
                    var sig_date_time: String,
                    var sig_duration_hms: String,
                    var sig_duration_milli: Int,
                    var sig_weather_full: Int,
                    var sig_temp: Int)

FireStoreSetup 类中:首次初始化发生时 ->

val sighting = Sighting(deviceId!!,
                        0,
                        0,
                        0,
                        strDate.substring(0, 4),
                        strDate.substring(5, 7),
                        strDate.substring(8, 10),
                        strDate.substring(11),
                        strDate,
                        "00:00:00",
                        0,
                        0,
                        0)

                db.collection("users").document(docname!!)
                        .set(sighting)
                        .addOnSuccessListener {
                            Log.d(_tag, "DocumentSnapshot successfully written!")
                            setShared(context,"doc_name",docname!!)}
                        .addOnFailureListener { e -> Log.w(_tag, "Error writing document", e) }

然后将数据写入服务器很有趣

fun addValue(key:String,value:Any?){
        val docData = HashMap<String,Any?>()
        docData.put(key, value)
        FirebaseFirestore.getInstance().collection("users").document(docname!!)
                .set(docData, SetOptions.merge())
    }

 fun readValue(){
        val docRef = FirebaseFirestore.getInstance().collection("users").document(docname!!)
        docRef.addSnapshotListener(object:EventListener<DocumentSnapshot> {
            override fun onEvent(snapshot:DocumentSnapshot?, e:FirebaseFirestoreException?) {
                if (e != null)
                {
                    Log.w("firestore", "Listen failed.", e)
                }
                if (snapshot != null && snapshot.exists())
                {
                    Log.d("firestore", "Current data: " + snapshot.getData())
                    FragmentHome.vars=snapshot.getData()
                }
                else
                {
                    Log.d("firestore", "Current data: null")
                }
            }
        })
    }

FragmentHome 中:

companion object {
        val itemsMenu = ArrayList<MenuData>()
        var vars: MutableMap<String,Any>? =null

        fun newInstance(value: Int): FragmentHome {
            val args = Bundle()
            args.putInt("menu", value)
            val fragment = FragmentHome()
            fragment.arguments = args
            return fragment
        }

    }

override fun onResume() {
        super.onResume()
        FireStoreSetup().readValue()
        when (_menu){
            0-> switchRecycler(1,0)
            1-> switchRecycler(0,0)
        }
    }

然后从fragmentHome,将其替换为具有firestore值的新片段:

val situ= vars!!["sig_wit_situation_type"].toString().toInt()
            val env= vars!!["sig_env_background_type"].toString().toInt()
            val grd= vars!!["sig_ground_type"].toString().toInt()
reFrag(FragmentSitu.newInstance(situ,env,grd), 1)

我们在新的 FragmentSitu 片段中的位置:

companion object {
        fun newInstance(situ: Int,env: Int,grd: Int): FragmentSitu {
            val args = Bundle()
            args.putInt("sig_wit_situation_type", situ)
            args.putInt("sig_env_background_type", env)
            args.putInt("sig_ground_type", grd)

            val fragment = FragmentSitu()
            fragment.arguments = args
            return fragment
        }
    }

感谢 Franck 和 docRef.addSnapshotListener,它可以毫无延迟地在线和离线工作。

** 必须有更好的方法从onEvent(snapshot:DocumentSnapshot?) 中捕获snapshot.getData() 结果,因为我希望直接从snapshot.getData()["situ"] 设置我的片段参数 FragmentSitu.newInstance(situ,env,grd),@ 987654332@...

【问题讨论】:

    标签: android firebase kotlin google-cloud-firestore persistent


    【解决方案1】:

    firebaser 在这里

    Firestore 将您在设备上写入的数据保存到本地数据库中。因此,下次启动应用程序时,它确实能够读取相同的数据,即使设备从未连接到 Firebase 服务器。

    当您的应用首次尝试从 Firestore 读取数据时,它会尝试建立与其服务器的连接。如果您是using get() calls to read the data,Firestore 将等待该连接建立或失败,然后再返回数据。这意味着此初始呼叫可能需要相当长的时间。我们知道这可能会导致您的应用用户出现不良行为,因此我们正在寻找改善这种行为的方法。

    同时,考虑using realtime listeners 读取相同的数据。这些侦听器在这种情况下的行为不同,将/可能提供两次结果:

    1. 第一个快照是直接给出的,来自本地缓存。
    2. 第二个快照稍后会在客户端从云数据库得到响应后给出。

    【讨论】:

    • 完美,谢谢弗兰克!一切都设置好并进行测试后,我将发布一些代码。
    • 从 'onEvent' 监听器中读取 'snapshot.getData()' 键的最佳方法是什么,因为它设置为可为空的 'snapshot:DocumentSnapshot?',我们需要阅读例如 Int 数据,哪些不可为空?函数在 Kotlin 中返回 Unit,以免说 Void。
    【解决方案2】:

    正如offical documentation 所说,

    Cloud Firestore 支持离线数据持久性。此功能会缓存您的应用正在使用的 Cloud Firestore 数据的副本,以便您的应用可以在设备离线时访问数据。

    但要使用此功能,您至少需要一个与数据库的连接。这意味着您的应用程序必须至少连接一次互联网。之后,您就可以对缓存的数据进行写、读、听和查询了。

    如果您想在活动或片段之间使用数据,我建议您使用IntentSharedPreferences,它可以在整个应用程序中保存您的数据。

    【讨论】:

    • 谢谢 Alex,现在我将更改 init 的设置方式,因为应用程序至少需要连接一次。在查询数据之前,我当然需要使用 OnCompleteListener() 检查文档是否在线存在。
    • 是的,在对文档进行操作之前验证文档是否存在是一种很好的做法。
    猜你喜欢
    • 2018-08-02
    • 2020-01-27
    • 1970-01-01
    • 2020-07-14
    • 2019-03-06
    • 1970-01-01
    • 2021-10-27
    • 2022-12-15
    • 2015-12-23
    相关资源
    最近更新 更多