You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin聊天应用Firebase Realtime DB离线持久化问题咨询

问题描述

我用Kotlin开发Android聊天应用,消息存储在Firebase Realtime Database中。想知道能否通过Realtime DB的持久化功能保存所有消息,让用户离线时也能读取?目前已开启持久化,但打开聊天界面看不到任何消息,怀疑是内存相关问题。

另外,我了解到Realtime Database缓存上限为10MB,能不能像Firestore那样调整缓存大小?如果无法使用缓存持久化,有什么替代方案?


持久化与同步代码(主Activity中)

Firebase.database.setPersistenceEnabled(true)
Firebase.database.setLogLevel(Logger.Level.DEBUG)
val settings = FirebaseFirestoreSettings.Builder()
    .setCacheSizeBytes(FirebaseFirestoreSettings.CACHE_SIZE_UNLIMITED)
    .build()
var db : FirebaseFirestore = FirebaseFirestore.getInstance()
db.firestoreSettings = settings
val scoresRef = Firebase.database.getReference("chats")
scoresRef.keepSynced(true)

读取消息代码

mDbRef.child("chats").child(senderRoom!!).child("messages")
    .addValueEventListener(object : ValueEventListener {
        @SuppressLint("NotifyDataSetChanged")
        override fun onDataChange(snapshot: DataSnapshot) {

            messageList.clear()

            for (postSnapshot in snapshot.children) {
                val message = postSnapshot.getValue(Message::class.java)
                messageList.add(message!!)
            }
            messageAdapter.notifyDataSetChanged()
            messageRecyclerView.scrollToPosition(messageAdapter.itemCount - 1)
        }

        override fun onCancelled(error: DatabaseError) {
            TODO("Not yet implemented")
        }
    })

相关日志

D/WebSocket: ws_2 - WebSocket reached EOF.
D/WebSocket: ws_2 - WebSocket error.
    com.google.firebase.database.tubesock.WebSocketException: IO Exception
        at com.google.firebase.database.tubesock.WebSocketWriter.runWriter(WebSocketWriter.java:159)
        at com.google.firebase.database.tubesock.WebSocketWriter.access$000(WebSocketWriter.java:30)
        at com.google.firebase.database.tubesock.WebSocketWriter$1.run(WebSocketWriter.java:47)
        at java.lang.Thread.run(Thread.java:1012)
     Caused by: java.net.SocketException: Socket closed
        at com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.writeInternal(ConscryptEngineSocket.java:690)
        at com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.write(ConscryptEngineSocket.java:661)
        at java.nio.channels.Channels$WritableByteChannelImpl.write(Channels.java:460)
        at com.google.firebase.database.tubesock.WebSocketWriter.writeMessage(WebSocketWriter.java:138)
        at com.google.firebase.database.tubesock.WebSocketWriter.runWriter(WebSocketWriter.java:152)
        at com.google.firebase.database.tubesock.WebSocketWriter.access$000(WebSocketWriter.java:30) 
        at com.google.firebase.database.tubesock.WebSocketWriter$1.run(WebSocketWriter.java:47) 
        at java.lang.Thread.run(Thread.java:1012) 
D/WebSocket: ws_2 - closed

解决方案

一、Realtime DB持久化能否实现离线读取?

可以,但你的代码存在几个关键问题导致离线无数据:

  1. keepSynced(true)作用范围错误:你给chats根节点开启同步,但实际读取的是chats/{senderRoom}/messages子节点。Realtime DB的同步是节点级别的,根节点同步不会自动覆盖所有子节点,还会占用大量缓存,反而可能清理目标节点的缓存数据。
  2. Firestore缓存配置无效:你写的Firestore缓存设置和Realtime DB完全无关,属于冗余代码,可直接删除。
  3. 持久化初始化时机不当:setPersistenceEnabled(true)应在应用初始化阶段(比如Application类的onCreate方法)调用,而非主Activity中,避免重复初始化引发异常。

修复步骤:

  • 删除所有Firestore相关代码;
  • 给实际读取的messages节点设置同步:
    val messagesRef = mDbRef.child("chats").child(senderRoom!!).child("messages")
    messagesRef.keepSynced(true)
    
  • 将Firebase.database.setPersistenceEnabled(true)移至自定义Application类中,确保全局仅初始化一次。

二、能否调整Realtime DB的缓存大小?

不能。Realtime Database客户端缓存上限固定为10MB,无法像Firestore那样自定义缓存容量。当缓存达到上限时,SDK会自动清理最久未使用的数据。

三、缓存持久化的替代方案

  1. 本地数据库存储:使用Room或SQLite将消息本地持久化,每次从Realtime DB同步新消息时,同时写入本地库。离线时直接读取本地数据,在线时再同步云端更新。
  2. 分页加载消息:避免一次性同步所有消息,按时间分页加载(比如每次加载最近50条),控制缓存占用,避免触发10MB上限。
  3. 定期清理旧消息:在云端和本地定期清理超过指定时长的旧消息,减少数据量,降低缓存压力。

关于WebSocket日志错误

日志中的Socket关闭错误是离线状态下的正常现象,Realtime DB会在网络恢复后自动重连,无需额外处理。


内容的提问来源于stack exchange,提问作者LeoBe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:55:31