.NET MAUI应用重操作生命周期:数据加载时机与对象已释放异常
MAUI页面数据加载优化与Disposed异常修复
问题根源分析
- 导航卡顿:当前在
OnAppearing同步调用数据加载函数,即便内部开启线程,若函数直接操作UI(比如更新列表数据源),仍会阻塞UI线程导致导航卡顿; - 返回时的Disposed异常:从其他页面返回时,原页面可能已被系统回收释放,但后台数据加载线程仍在执行UI更新操作,试图访问已销毁的
FrameRenderer,因此抛出ObjectDisposedException。
具体解决方案
1. 引入取消令牌跟踪页面生命周期
添加CancellationTokenSource,在页面消失时取消未完成的后台任务,避免访问已释放的UI元素:
private CancellationTokenSource _cts; protected override void OnAppearing() { base.OnAppearing(); // 重置取消令牌 _cts?.Dispose(); _cts = new CancellationTokenSource(); // 异步加载数据,不阻塞UI _ = LoadPendingListFromLocalDbAsync(_cts.Token); } protected override void OnDisappearing() { // 取消后台任务并释放资源 _cts?.Cancel(); _cts?.Dispose(); base.OnDisappearing(); }
2. 改造数据加载函数为异步并隔离UI操作
确保数据库操作在后台线程执行,UI更新切回主线程,同时响应取消令牌:
private async Task LoadPendingListFromLocalDbAsync(CancellationToken token) { try { // 数据库查询放在后台线程,避免阻塞UI var listData = await Task.Run(() => { // 检查任务是否已取消 token.ThrowIfCancellationRequested(); // 这里替换成你的本地数据库查询逻辑 return YourLocalDb.GetPendingItems(); }, token); token.ThrowIfCancellationRequested(); // 切回主线程更新UI await Device.InvokeOnMainThreadAsync(() => { // 更新列表数据源 YourListView.ItemsSource = listData; }, token); } catch (OperationCanceledException) { // 任务被取消,无需处理 } catch (Exception ex) { // 处理其他加载异常 Console.WriteLine($"数据加载失败:{ex.Message}"); } }
3. 替换原OnAppearing的同步调用
把原来的同步调用替换为上面的异步实现,确保UI线程不被阻塞。
额外注意点
- 不要在
OnAppearing中使用async void(除非是事件处理),用_ = 异步方法()的方式避免同步阻塞; - 所有UI相关操作必须回到主线程执行,MAUI中使用
Device.InvokeOnMainThreadAsync是可靠方式; - 取消令牌要在页面消失时及时销毁,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Vishva Vijay
相关产品推荐
相关产品推荐

