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

MAUI中使用AppShell FlyoutHeader与IsBusy实现全局ActivityIndicator崩溃问题

解决方案:全局ActivityIndicator设置IsBusy崩溃问题

问题根源分析

崩溃大概率由两个原因导致:

  1. UI线程访问异常:虽然await后理论上会回到UI线程,但数据库异步操作可能导致同步上下文丢失,直接设置Shell.Current.IsBusy时不在UI线程,触发跨线程访问UI控件的异常。
  2. BindingContext不匹配:FlyoutHeader的默认BindingContext并非Shell实例,导致绑定的IsBusy属性未正确关联到Shell的IsBusy,引发绑定更新时的异常。

方案1:强制在UI线程更新IsBusy

无论异步操作上下文如何,通过MainThread确保UI属性的更新在主线程执行:

public async static Task<List<T>> GetAsync<T>(Expression<Func<T, bool>>? predicate = null, bool includeActiveOnly = true) where T : BaseModel, new()
{
    // 确保在UI线程设置IsBusy为true
    MainThread.BeginInvokeOnMainThread(() => 
    {
        if (Shell.Current != null)
            Shell.Current.IsBusy = true;
    });
    
    var query = DbContext.Table<T>();

    if (includeActiveOnly)
        query = query.Where(x => x.IsActive == true);

    if (predicate != null)
        query = query.Where(predicate);

    query = query.OrderByDescending(x => x.DateAdded);
    
    var list = await query.ToListAsync();
    
    // 同样在UI线程设置IsBusy为false
    MainThread.BeginInvokeOnMainThread(() => 
    {
        if (Shell.Current != null)
            Shell.Current.IsBusy = false;
    });
    
    return list;
}

同时修正FlyoutHeader的绑定,确保关联到Shell的IsBusy属性:

<!-- 先给Shell设置x:Name -->
<Shell x:Name="rootShell" ...>
    <Shell.FlyoutHeader>
        <StackLayout x:Name="profileCard" BindingContext="{x:Reference rootShell}">
            <ActivityIndicator IsRunning="{Binding IsBusy}"
                               IsVisible="{Binding IsBusy}"
                               HorizontalOptions="Center"
                               VerticalOptions="Center"
                               Color="Red" />
            <!-- 其他布局内容 -->
        </StackLayout>
    </Shell.FlyoutHeader>
</Shell>

方案2:使用全局状态管理(更可靠)

避免直接依赖Shell.Current,改用单例状态类管理全局IsBusy状态,降低耦合度:

  1. 创建全局状态类:
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class AppGlobalState : INotifyPropertyChanged
{
    private bool _isBusy;
    public bool IsBusy
    {
        get => _isBusy;
        set
        {
            if (_isBusy != value)
            {
                _isBusy = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // 单例实例
    public static AppGlobalState Instance { get; } = new AppGlobalState();
}
  1. 修改FlyoutHeader绑定:
<!-- 顶部声明命名空间前缀,替换为你的项目命名空间 -->
xmlns:local="clr-namespace:你的项目命名空间"

<Shell.FlyoutHeader>
    <StackLayout x:Name="profileCard">
        <ActivityIndicator IsRunning="{Binding Source={x:Static local:AppGlobalState.Instance}, Path=IsBusy}"
                           IsVisible="{Binding Source={x:Static local:AppGlobalState.Instance}, Path=IsBusy}"
                           HorizontalOptions="Center"
                           VerticalOptions="Center"
                           Color="Red" />
        <!-- 其他布局内容 -->
    </StackLayout>
</Shell.FlyoutHeader>
  1. 更新GetAsync方法:
public async static Task<List<T>> GetAsync<T>(Expression<Func<T, bool>>? predicate = null, bool includeActiveOnly = true) where T : BaseModel, new()
{
    MainThread.BeginInvokeOnMainThread(() => AppGlobalState.Instance.IsBusy = true);
    
    var query = DbContext.Table<T>();

    if (includeActiveOnly)
        query = query.Where(x => x.IsActive == true);

    if (predicate != null)
        query = query.Where(predicate);

    query = query.OrderByDescending(x => x.DateAdded);
    
    var list = await query.ToListAsync();
    
    MainThread.BeginInvokeOnMainThread(() => AppGlobalState.Instance.IsBusy = false);
    
    return list;
}

额外注意事项

  • 加入空值判断:操作Shell.Current前先检查是否为null,避免Shell未初始化时的空引用异常。
  • 异常捕获:可以在设置IsBusy的代码块中添加try-catch,记录日志排查问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:05:54