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

Xamarin Forms 结合SQL实现条目删除时偶发重复显示问题排查

问题根因分析

该问题偶发的核心原因是异步操作时序不稳定、集合更新线程不安全两类问题叠加:

  • 加载命令并发执行:删除事件回调中采用_ = ExecuteLoadItemsCommand()的火并忘写法,无等待机制,短时间多次触发删除时会出现多个加载命令并发执行。此时可能出现后触发的加载先完成数据拉取,先触发的加载晚返回后重复添加数据的情况,导致数据源里出现重复条目。
  • ObservableCollection跨线程操作:ExecuteLoadItemsCommand中对Items的Clear、Add操作未强制在UI线程执行,当异步回调回到非UI线程时,CollectionView无法正确响应集合变更通知,会出现UI渲染和数据源不一致的视觉重复,手动刷新触发全量UI更新后才会恢复正常。
  • SQLite连接多实例冲突:每次删除操作都新建SQLiteAsyncConnection实例,多操作并发时可能出现删除操作还未落盘,加载命令就已读取到未删除的旧数据,看起来像删除失败出现重复条目。
修复方案

可按优先级选择以下修复措施:

优先推荐:优化删除逻辑,避免全量刷新

删除完成后直接从数据源移除对应条目,不需要重新拉取全量数据,性能更高且不会出现并发加载问题:

private async Task OnDeleteItem(Item selectedItem)
{
    await LocalDatabaseService.DeleteItem(selectedItem);
    // 强制在UI线程操作集合,保证变更能被CollectionView正确响应
    await MainThread.InvokeAsync(() =>
    {
        if (Items.Contains(selectedItem))
        {
            Items.Remove(selectedItem);
        }
    });
}

调整后可以删除原删除事件回调中的加载逻辑,不需要再触发全量数据刷新。

基础修复:修复加载命令的并发和线程安全问题

如果需要保留全量刷新逻辑,需给加载命令加防重入锁,并强制集合操作在UI线程执行:

private bool _isLoading;
async Task ExecuteLoadItemsCommand()
{
    if (_isLoading) return;
    _isLoading = true;
    IsBusy = true;

    try
    {
        await MainThread.InvokeAsync(() => Items.Clear());
        var items = await LocalDatabaseService.GetAllItems();
        await MainThread.InvokeAsync(() =>
        {
            foreach (var item in items)
            {
                Items.Add(item);
            }
        });
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
    }
    finally
    {
        IsBusy = false;
        _isLoading = false;
    }
}

底层优化:SQLite连接改为单例模式

避免多连接并发导致的数据读写不一致问题:

//  LocalDatabaseService中添加单例连接逻辑
private static SQLiteAsyncConnection _db;
private static SQLiteAsyncConnection GetDbConnection()
{
    if (_db == null)
    {
        var databasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "MyData3.db");
        _db = new SQLiteAsyncConnection(databasePath);
    }
    return _db;
}

public async Task DeleteItem(Item item)
{
    var db = GetDbConnection();
    await db.DeleteAsync(item);
    OnDeletedItem?.Invoke();
}

可选优化:调整CollectionView缓存策略

避免cell复用导致的视觉重复,在XAML中添加缓存策略属性:

<CollectionView x:Name="ItemsListView"
        ItemsSource="{Binding Items}"
        SelectionMode="None"
        CachingStrategy="RecycleElementAndDataTemplate">

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:48:03