Xamarin.Forms新手求助:用Akavache实现SignalR聊天消息持久化失败
解决Akavache存储聊天消息显示系统代码的问题
我看了你的代码,问题主要出在对Akavache异步操作的错误处理以及存储单条消息而非列表这两点上,导致你看到的是订阅对象的字符串(也就是所谓的“系统代码”),而不是实际的聊天内容。下面一步步给你修正:
核心问题分析
- Akavache的
GetObject<T>返回的是IObservable<T>:你直接调用Subscribe(...).ToString(),得到的是订阅操作本身的对象字符串,而不是消息的实际内容。 - 每次只存储单条消息:新消息会覆盖旧的,而且读取时也没有正确获取历史消息列表。
- 异步操作未正确处理:Akavache的方法都是异步的,同步写法会导致数据还没获取到就执行后续代码,出现异常数据。
修正后的代码实现
我们需要把聊天消息列表作为一个整体存储,同时正确处理Akavache的异步操作:
1. 重构ViewModel中的消息存储与读取逻辑
// 将消息处理逻辑封装为异步方法 public async Task ProcessNewMessage(string message, bool isMe) { List<ChatMessage> existingMessages = new List<ChatMessage>(); // 尝试读取历史消息列表 try { // 用FirstAsync()获取Observable的实际数据,await等待异步操作完成 existingMessages = await BlobCache.LocalMachine.GetObject<List<ChatMessage>>("ChatMessages") .FirstAsync(); } catch (KeyNotFoundException) { // 首次使用无存储记录,初始化空列表 existingMessages = new List<ChatMessage>(); } // 创建新消息 var newMessage = new ChatMessage() { Message = message, IsOwnMessage = isMe, IsSystemMessage = false, ActionTime = DateTime.Now.ToString("hh:mm tt") }; // 更新消息列表并同步到UI existingMessages.Add(newMessage); Device.BeginInvokeOnMainThread(() => { ChatMessageList.Clear(); foreach (var msg in existingMessages) { ChatMessageList.Add(msg); } MessagingCenter.Send(this, "SCROLL_BOTTOM"); }); // 将更新后的列表存入Akavache await BlobCache.LocalMachine.InsertObject("ChatMessages", existingMessages); }
2. 调用异步方法处理新消息
当用户发送或收到新消息时,直接调用这个方法:
// 示例:用户发送消息时 await ProcessNewMessage(inputMessage, isMe: true);
3. 页面加载时读取历史消息
在ChatPage的ViewModel初始化或页面Appearing事件中,加载历史消息:
public async Task LoadHistoryMessages() { try { var existingMessages = await BlobCache.LocalMachine.GetObject<List<ChatMessage>>("ChatMessages") .FirstAsync(); Device.BeginInvokeOnMainThread(() => { ChatMessageList.Clear(); foreach (var msg in existingMessages) { ChatMessageList.Add(msg); } MessagingCenter.Send(this, "SCROLL_BOTTOM"); }); } catch (KeyNotFoundException) { // 无历史消息,无需操作 } }
关键修改点说明
- 存储消息列表而非单条消息:确保所有历史消息都被保留,不会被新消息覆盖。
- 正确处理Observable异步结果:用
await+FirstAsync()获取Akavache返回的实际数据,避免将订阅对象直接转为字符串。 - UI线程更新集合:Xamarin.Forms的UI控件只能在主线程更新,通过
Device.BeginInvokeOnMainThread确保列表更新不会触发跨线程异常。 - 捕获初始化异常:首次使用时无存储记录会抛出
KeyNotFoundException,捕获后初始化空列表即可正常执行。
这样修改后,你就能正确显示聊天消息,而不是系统代码了。
内容的提问来源于stack exchange,提问作者Xsamms
相关产品推荐
相关产品推荐

