You need to enable JavaScript to run this app. Xamarin.Forms FreshMvvm 如何确保OnStartCall在VideoCallPage加载完成后触发
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms FreshMvvm 如何确保OnStartCall在VideoCallPage加载完成后触发

FreshMvvm 下视频通话页时序错位的调整方案

时序错位的核心根源是两处:

  • 你重写的Init方法用了async void签名,这类方法的执行状态外部无法追踪,PushPage的await只会等待页面入栈的动作完成,根本不会等Init内部的异步逻辑跑完
  • 静态事件OnStartCall的触发逻辑完全脱离PageModel的生命周期,没有和页面初始化完成的状态做任何绑定

落地调整方案

方案1:替换异步初始化签名,对齐FreshMvvm的可等待生命周期

FreshMvvm的FreshBasePageModel本身提供了可被导航逻辑等待的异步初始化入口InitAsync,返回Task,导航服务的PushPage动作会自动await这个方法的执行完成,把原来的async void Init的逻辑全部迁过去就能解决大部分错位问题:

  1. 在VideoCallPageModel里删掉原有的public async override void Init(object initData),重写InitAsync方法,并加一个初始化状态标记:
// 标记页面初始化是否完成
private bool _isInitialized;
public bool IsInitialized
{
    get => _isInitialized;
    set => SetProperty(ref _isInitialized, value);
}

public override async Task InitAsync(object initData)
{
    // 把原来写在async void Init里的所有异步逻辑全部迁到这里
    await InitCallRenderViewAsync();
    await LoadLocalCallConfigAsync();
    // 所有初始化逻辑跑完后,标记状态为完成
    IsInitialized = true;
}
  1. 调整App.xaml.cs里NewCall方法的逻辑,拿到PageModel的实际实例,等初始化完成后再触发事件:
await Xamarin.Essentials.MainThread.InvokeOnMainThreadAsync(async () =>
{          
    if (!IsVideoCallViewOpen)
    {          
        var navService = FreshIOC.Container.Resolve<IFreshNavigationService>(FreshMvvm.Constants.DefaultNavigationServiceName);
        // 解析Page的同时拿到绑定的PageModel实例,不要重复Resolve
        var videoCallPage = FreshPageModelResolver.ResolvePageModel<VideoCallPageModel>();
        var videoCallPageModel = videoCallPage.BindingContext as VideoCallPageModel;
        
        // PushPage的await会自动等待InitAsync的所有逻辑跑完
        await navService.PushPage(videoCallPage, null);

        // 兜底等待,防止极端场景下状态标记延迟
        while (!videoCallPageModel.IsInitialized)
        {
            await Task.Delay(30);
        }
    }

    VideoCallMessage caller = JsonConvert.DeserializeObject<VideoCallMessage>(message);
    VideoCallPeer peer = new VideoCallPeer(caller.UserId, caller.UserName, caller.FirstName);
    // 等所有初始化流程走完再触发事件
    OnStartCall?.Invoke(null, peer);
});

方案2:把通话逻辑闭环到PageModel内部,彻底解耦外部触发时序

这个方案稳定性更高,不需要外部代码关心页面什么时候初始化完成,把通话参数当导航值传递,让PageModel自己在初始化完成后处理来电逻辑:

  1. 定义导航参数类,封装通话需要的对方信息:
public class VideoCallNavParams
{
    public VideoCallPeer Caller { get; set; }
}
  1. 调整NewCall的逻辑,不再单独触发静态事件,而是把对方信息当导航参数传给目标页面:
await Xamarin.Essentials.MainThread.InvokeOnMainThreadAsync(async () =>
{
    VideoCallMessage caller = JsonConvert.DeserializeObject<VideoCallMessage>(message);
    VideoCallPeer peer = new VideoCallPeer(caller.UserId, caller.UserName, caller.FirstName);
    var navService = FreshIOC.Container.Resolve<IFreshNavigationService>(FreshMvvm.Constants.DefaultNavigationServiceName);

    if (!IsVideoCallViewOpen)
    {          
        // 构造导航参数,随页面一起传递
        var navParams = new VideoCallNavParams { Caller = peer };
        await navService.PushPage<VideoCallPageModel>(navParams, null);
    }
    else
    {
        // 页面已经打开的场景,直接把peer传给当前栈内的PageModel实例处理
        var currentCallPageModel = 导航栈顶层页面?.BindingContext as VideoCallPageModel;
        currentCallPageModel?.HandleIncomingCall(peer);
    }
});
  1. 在VideoCallPageModel的InitAsync里,先做完所有页面初始化,再处理来电逻辑:
public override async Task InitAsync(object initData)
{
    // 先跑页面自身的全部初始化逻辑
    await InitCallUiResourcesAsync();
    WireUpUiEventHandlers();

    // 初始化完成后,从导航参数里取来电信息,走原有StartCallHandler的逻辑
    var navParams = initData as VideoCallNavParams;
    if (navParams?.Caller != null)
    {
        StartCallHandler(this, navParams.Caller);
    }
}

// 补一个公开的来电处理方法,应对页面已打开的来电场景
public void HandleIncomingCall(VideoCallPeer remotePeer)
{
    StartCallHandler(this, remotePeer);
}

避坑提醒

  • 别继续用async void的Init重写,这个签名的方法FreshMvvm内部是直接同步调用、不等待执行结果的,所有写在里面的异步逻辑都是“fire and forget”,根本没法对齐时序
  • 不要把需要等待的初始化逻辑放到页面的OnAppearing生命周期里,这个节点的触发时机晚于Init,会比页面入栈的await返回点更晚,反而会拉大时间差
  • 如果必须保留现有静态事件OnStartCall的逻辑,记得在事件的订阅端(也就是VideoCallPageModel里)加判断,只有当自身初始化状态为完成时才执行StartCallHandler,没完成的话先把peer存下来,等初始化完成后再补跑逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.10 11:36:04