初始化 Xamarin.Forms 应用程序时找不到调用异步方法的方法

Eri*_*Lam 5 c# android async-await xamarin.forms uwp

异步/等待线程让我发疯。我对异步初始化的可能性做了很多研究。

问题就在这里。我试图根据当前应用程序状态将我的应用程序加载到特定页面。确定应用程序的状态。它包括扫描到数据文件夹。为了Storage API在UWP中使用。我必须在 Xamarin Forms 中创建async依赖项服务。

我在这里使用单例模式和一个AppManager类。

应用管理器.cs

public class AppManager{
    public static AppManager Instance = new AppManager();
    public List<Jobs> JobList = new List<Jobs>();

    public async Task InitializeAsync(){
        JobList.AddRange(await DependencyService.Get<IFileService>().GetJobs());
    }

    public bool JobExists(string jobName){
        return JobList.Any(j => j.Name == jobName);
    }
}
Run Code Online (Sandbox Code Playgroud)

当应用程序启动时,需要JobList首先从 Data 文件夹加载。然后查看JobList并确定要导航到哪个页面。

我当前想做的是从类的构造函数中调用下面的代码App

应用程序.xaml.cs

InitializeComponent(); // Default

var appManager = AppManager.Instance;
appManager .InitializeAsync();
if(appManager .JobExists("JobA")){
    MainPage = new PageA();
}else{
    MainPage = new PageB();
}
Run Code Online (Sandbox Code Playgroud)

这总是会让我发现PageB列表是空的,因为初始化尚未完成。这是由于在线程async中运行代码引起的synchronous

我在这个博客中阅读了有关创建异步构造函数的多种方法。await但是,他们仍然要求我在调用中创建一个函数,这在这种情况下是不可能的。

我还尝试将整个App()构造函数代码移动到一个async Task函数中,然后在构造函数中调用InitializeAsync().Wait()。但是,Xamarin Forms 会在运行时抱怨。正如App参考.nullMainPage

我想知道是否可以使用等待的函数来实现完整的初始化而不涉及不良实践(例如 async void)?我也有一些关于如何解决这种情况的想法,例如使用SystemIO而不是Storage API仍然适用于 Xamarin Forms UWP。但我真的很想深入研究async功能,而不仅仅是让它发挥作用。谢谢。

Mar*_*und 3

问题是 Xamarin.Forms 期望MainPage在初始化后立即设置。如果你使用asynccall,你需要等待它完成,这将不可避免地导致XF抱怨页面丢失。

对于这个问题有三种解决方案。

您可以在启动时显示临时“加载页面”。在这种情况下,您首先设置MainPage一个页面,通知用户应用程序正在加载:

public App()
{
   MainPage = new LoadingPage();
}
Run Code Online (Sandbox Code Playgroud)

然后您继续覆盖async中的操作OnStart

protected override async void OnStart()
{
   var appManager = AppManager.Instance;
   await appManager.InitializeAsync();
   if(appManager .JobExists("JobA"))
   {
      MainPage = new PageA();
   }
   else
   {
      MainPage = new PageB();
   }
}
Run Code Online (Sandbox Code Playgroud)

第二个选项是在 Xamarin.Forms初始化之前连接异步初始化任务。对于 UWP,您可以转到 UWP 项目的App.xaml.cs文件并将其放入OnLaunchedXamarin.Forms 初始化之前的方法重写中:

protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
    ...

    var appManager = AppManager.Instance;
    await appManager.InitializeAsync();
    Xamarin.Forms.Forms.Init(e);

    ...
}
Run Code Online (Sandbox Code Playgroud)

这只会延长基于 UWP 的启动屏幕,但当 Xamarin.Forms 初始化时,它AppManager已经被初始化。

Adam Pedley 的这篇博客文章描述了您的最终选择。它允许您在 UI 线程上运行任务,但会阻塞,直到使用TaskHelper完成任务为止。

Exrin.Common.ThreadHelper.Init(SynchronizationContext.Current);
Exrin.Common.ThreadHelper.RunOnUIThread(async () => { await MyMethod(); });
Run Code Online (Sandbox Code Playgroud)

这可能应该是最后一个选择,因为它可以被认为是一种黑客行为,而不是一个正确的解决方案。