Xamarin中如何借助FirebaseDatabase.net实现Firebase Realtime离线同步
实现方案
1 开启Firebase内置离线持久化
Firebase Realtime Database 本身自带离线缓存能力,开启后写入、读取操作在离线时会自动操作本地缓存,网络恢复后自动同步本地变更到云端,是成本最低的实现方案。
修改你的FirebaseService初始化代码,开启离线支持:
public class FirebaseService { FirebaseClient firebase; public FirebaseService() { firebase = new FirebaseClient("https://xxxxxxx-xxxx-xxxx.firebaseio.com/", new FirebaseOptions { // 开启离线持久化,所有读写操作会优先走本地缓存,网络恢复自动同步 OfflineDatabaseEnabled = true }); } }
开启后你原有大部分代码不需要修改,就可以获得基础的离线能力:
- 离线时写入操作会存在本地缓存,联网后Firebase会自动同步到云端,不需要手动处理
- 离线时查询操作会返回本地缓存的已有数据
2 补充更稳定的待同步队列(可选,适合对数据可靠性要求高的场景)
如果担心Firebase内置缓存丢数据,可以额外加一层本地待同步队列,用SQLite或者Xamarin.Essentials的Preferences、SecureStorage存储待同步的Contato数据,步骤如下:
- 写入数据时先判断网络状态,在线直接调用PostAsync,离线就把数据存入本地待同步队列
- 注册网络状态变化监听,网络从离线变为在线时,遍历本地待同步队列,依次上传到云端,上传成功后删除本地队列里的对应数据
修改后的完整代码示例
using SQLite; // 需要安装sqlite-net-pcl包 using Xamarin.Essentials; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Firebase.Database; using Firebase.Database.Query; public class FirebaseService { private readonly FirebaseClient firebase; private readonly SQLiteAsyncConnection _db; public FirebaseService() { // 初始化Firebase,开启离线缓存 firebase = new FirebaseClient("https://xxxxxxx-xxxx-xxxx.firebaseio.com/", new FirebaseOptions { OfflineDatabaseEnabled = true }); // 初始化本地SQLite存待同步数据 var dbPath = Path.Combine(FileSystem.AppDataDirectory, "SyncQueue.db3"); _db = new SQLiteAsyncConnection(dbPath); _db.CreateTableAsync<PendingContato>().Wait(); // 监听网络状态变化,恢复联网时触发同步 Connectivity.ConnectivityChanged += async (s, e) => { if (e.NetworkAccess == NetworkAccess.Internet) { await SyncPendingData(); } }; } // 待同步数据模型 public class PendingContato : Contato { [PrimaryKey, AutoIncrement] public int SyncId { get; set; } } public async Task AddContato(int id, string nome, string email) { var contato = new Contato() { Id = id, Nome = nome, Email = email }; if (Connectivity.NetworkAccess == NetworkAccess.Internet) { // 在线直接上传 await firebase.Child("Contatos").PostAsync(contato); } else { // 离线存入本地待同步队列 await _db.InsertAsync(new PendingContato { Id = id, Nome = nome, Email = email }); } } public async Task<List<Contato>> GetContatos() { // 先拿云端/离线缓存的数据 var cloudData = (await firebase.Child("Contatos").OnceAsync<Contato>()) .Select(item => item.Object) .ToList(); // 再合并本地待同步的数据,避免用户看不到自己刚离线提交的数据 var pendingData = await _db.Table<PendingContato>().ToListAsync(); cloudData.AddRange(pendingData); return cloudData; } // 同步本地待队列数据 private async Task SyncPendingData() { var pendingList = await _db.Table<PendingContato>().ToListAsync(); foreach (var item in pendingList) { try { await firebase.Child("Contatos").PostAsync(new Contato { Id = item.Id, Nome = item.Nome, Email = item.Email }); // 上传成功删除本地记录 await _db.DeleteAsync(item); } catch { // 上传失败保留,下次再试 continue; } } } } // 你的原有Contato模型 public class Contato { public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } }
注意事项
- Firebase内置离线缓存的存储上限是10MB,如果你的数据量很大,建议用自定义待同步队列的方案
- 每次App启动时可以主动调用一次
SyncPendingData(),避免App启动时已联网、没有触发网络状态变化导致的待同步数据积压 - 使用Xamarin.Essentials的Connectivity需要在Android项目中添加
ACCESS_NETWORK_STATE权限,iOS无需额外配置 - 如果不需要极高的数据可靠性,仅开启第一步的
OfflineDatabaseEnabled即可满足需求,无需额外开发队列逻辑
内容的提问来源于stack exchange,提问作者FernandoPaiva
相关产品推荐
相关产品推荐

