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

Xamarin.Forms新手求助:用Akavache实现SignalR聊天消息持久化失败

解决Akavache存储聊天消息显示系统代码的问题

我看了你的代码,问题主要出在对Akavache异步操作的错误处理以及存储单条消息而非列表这两点上,导致你看到的是订阅对象的字符串(也就是所谓的“系统代码”),而不是实际的聊天内容。下面一步步给你修正:

核心问题分析

  1. Akavache的GetObject<T>返回的是IObservable<T>:你直接调用Subscribe(...).ToString(),得到的是订阅操作本身的对象字符串,而不是消息的实际内容。
  2. 每次只存储单条消息:新消息会覆盖旧的,而且读取时也没有正确获取历史消息列表。
  3. 异步操作未正确处理: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 23:02:41