Xamarin Forms Prism框架下拍照返回后OnAppearing重复触发如何解决
根因说明
Prism的OnAppearing触发逻辑为只要页面回到可视栈顶就会执行,覆盖了相机/系统弹窗等原生组件关闭返回页面的场景,和仅后台恢复才刷新的需求不匹配,可通过新增状态标记区分触发场景解决。
实现修改
1. 新增状态标记与事件订阅
首先在ViewModel中新增状态字段,订阅应用级恢复事件,页面销毁时取消订阅避免内存泄漏:
private bool _isOpeningNativeComponent = false; private bool _isResumedFromBackground = false; // ViewModel构造函数 public YourViewModel(INavigationService navigationService) : base(navigationService) { // 仅当前页面监听应用恢复事件,不会全局生效 App.Current.Resumed += OnAppResumedFromBackground; } // 实现Prism的IDestructible接口,页面销毁时取消事件订阅 public override void Destroy() { App.Current.Resumed -= OnAppResumedFromBackground; base.Destroy(); } private void OnAppResumedFromBackground(object sender, EventArgs e) { // 标记当前为后台恢复场景 _isResumedFromBackground = true; }
2. 调整相机调用逻辑
打开相机前增加原生组件启动标记,调用完成后重置标记:
private async Task<bool> RecognizeUser() { if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported) { await App.Current.MainPage.DisplayAlert(AppResources.No_Camera, AppResources.No_camera_is_available_, AppResources.OK); return false; } // 标记即将打开原生相机,此时返回页面不需要刷新 _isOpeningNativeComponent = true; var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions { PhotoSize = Plugin.Media.Abstractions.PhotoSize.Small, CompressionQuality = 60, Directory = "Recognition", Name = DateTime.Now + "-Identify.jpg" }); // 相机调用完成,重置标记 _isOpeningNativeComponent = false; // 原有逻辑不变 if (file == null) { return false; } RecognitionResult = await Identify(file.GetStream()); if (RecognitionResult.ReturnType == null) { await App.Current.MainPage.DisplayAlert(AppResources.Alert, RecognitionResult.Status, AppResources.OK); return false; } bool result = await GetCurrentLocation(); return true; }
3. 重写OnAppearing逻辑
仅符合后台恢复、非原生组件返回的场景才执行刷新:
public async void OnAppearing() { if (_isResumedFromBackground && !_isOpeningNativeComponent) { await RefreshLogAndButtons(); } // 每次执行后重置标记,避免下次误触发 _isResumedFromBackground = false; }
优化建议
原RefreshLogAndButtons方法为async void类型,建议改为async Task,避免未捕获的异常直接抛到线程池导致崩溃。
如果你后续有其他会触发页面暂时消失的原生操作(比如权限弹窗、系统通讯录调用等),统一在调用前设置_isOpeningNativeComponent = true,调用完成后重置为false即可避免误刷新。
内容的提问来源于stack exchange,提问作者Alamzaib Farooq
相关产品推荐
相关产品推荐

