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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:57:02