Android设备联网后Firestore仍返回客户端离线异常求助
我遇到过不少开发者反馈这个棘手的问题,结合你提供的细节和官方的反馈,咱们来拆解下问题根源和可行的临时解决方案:
问题复盘
你已经做了正确的配置:禁用了Firestore的本地持久化(setPersistenceEnabled(false)),确认设备恢复联网后其他网络请求正常,但Firestore的文档获取请求却不稳定地抛出Failed to get document because the client is offline异常——有时马上成功,有时重试多次甚至等一分钟才恢复。升级SDK版本到11.8.0、甚至firestore-core 17.0.4也没能解决。
核心原因
根据你提到的官方确认,这是Firestore Android SDK内部的网络状态同步延迟问题:当设备从离线(比如飞行模式)恢复联网时,系统层面的网络状态已经更新,但Firestore客户端内部的连接检测机制没有及时同步这个状态,导致SDK仍然认为自己处于离线状态,从而拒绝发起网络请求。即使禁用了持久化,这个内部状态不同步的问题依然存在。
临时缓解方案
虽然官方还没给出修复时间表,但可以试试这几个方案来降低问题影响:
1. 主动触发网络重连
在确认设备联网后,主动调用enableNetwork()方法(即使已经禁用持久化,这个方法也能触发SDK重新检测网络连接状态),等重连成功后再发起请求:
// 先通过ConnectivityManager确认网络可用后执行 firestore.enableNetwork().addOnSuccessListener { // 网络连接已被Firestore确认,发起文档请求 val docRef = firestore.collection("foo").document("bar") docRef.get().addOnCompleteListener { task -> if (task.isSuccessful) { Log.d("FirestoreSourceSet", "Get document success") } else { Log.e("FirestoreSourceSet", "Get document error", task.exception) } } }
2. 给请求加智能重试机制
因为异常是间歇性的,给Firestore请求加上指数退避重试逻辑,针对"离线"异常自动重试,直到成功或达到最大次数:
private fun fetchDocumentWithRetry( docRef: DocumentReference, currentRetry: Int = 0, maxRetries: Int = 5 ) { docRef.get().addOnCompleteListener { task -> when { task.isSuccessful -> { Log.d("FirestoreSourceSet", "Get document success") } currentRetry < maxRetries -> { val exception = task.exception if (exception is FirebaseFirestoreException && exception.code == FirebaseFirestoreException.Code.UNAVAILABLE) { // 指数退避:每次重试延迟时间翻倍,避免频繁请求 val delayMs = (Math.pow(2.0, currentRetry.toDouble()) * 100).toLong() Handler(Looper.getMainLooper()).postDelayed({ fetchDocumentWithRetry(docRef, currentRetry + 1, maxRetries) }, delayMs) } else { Log.e("FirestoreSourceSet", "Non-retryable error", exception) } } else -> { Log.e("FirestoreSourceSet", "Max retries reached, request failed", task.exception) } } } } // 使用示例 val docRef = firestore.collection("foo").document("bar") fetchDocumentWithRetry(docRef)
3. 监听Firestore的同步状态
利用addSnapshotsInSyncListener来监听Firestore的内部同步状态,只有当SDK确认同步完成(即网络连接正常)后再发起请求:
val syncListener = firestore.addSnapshotsInSyncListener { isSyncing -> // isSyncing为false时,说明Firestore已完成与服务器的同步,连接状态正常 if (!isSyncing) { val docRef = firestore.collection("foo").document("bar") docRef.get().addOnCompleteListener { task -> // 处理请求结果 } // 移除监听,避免重复触发 syncListener.remove() } }
官方进展说明
目前官方已经确认这是一个SDK内部的bug,但暂时没有给出具体的修复时间。建议你持续关注Firestore SDK的版本更新日志,一旦官方发布修复版本,及时升级即可。
内容的提问来源于stack exchange,提问作者Matthieu Esnault

