【问题标题】:Perform async tasks on Startup在启动时执行异步任务
【发布时间】:2018-02-24 22:33:38
【问题描述】:

我想使用 Xamarin 执行下一步:

  • 当应用程序启动时会立即显示 splashScreen(我已经在下一个教程 https://channel9.msdn.com/Blogs/MVP-Windows-Dev/Using-Splash-Screen-with-Xamarin-Forms 中实现了这一点)

  • 执行数据库迁移(如果有)(以防用户更新应用并首次运行)

  • 从 db 读取用户数据(用户名和密码),调用 REST web 服务检查用户数据是否仍然有效。如果用户数据有效,则将用户重定向到 MainPage,否则重定向到 LoginPage

我已经阅读了关于Xamarin.Forms Async Task On Startup 的下一篇好文章。当前代码:

public class MainActivity :global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
  protected override void OnCreate (Bundle bundle)
  {
    base.OnCreate (bundle);
    global::Xamarin.Forms.Forms.Init (this, bundle);
    LoadApplication (new App ()); // method is new in 1.3
  }
}

// shared code - PCL lib for Android and iOS
public partial class App : Application
{
  public App()
  {
    InitializeComponent();
    // MainPage = new LoadingPage();
  }
}    
protected override async void OnStart()
{
  // Handle when your app starts
  await App.Database.Migrations();
  if( await CheckUser()) // reads user data from db and makes http request
    this.MainPage = new Layout.BrowsePage();
  else
    this.MainPage = new LoginPage();
 }

如果 MainPage 未在构造函数中设置,则在 iOS 和 Android 上将引发异常。我知道如果 async void 没有明确具有.Wait(),它不会等待 - Async void,但这是否意味着正在执行的线程仍在继续它的工作。

当执行线程遇到await App.Database.Migrations(); 时,它会暂停执行并等待等待任务完成。同时它继续它的工作(即 LoadApplication() 继续执行并期望 App.MainPage 现在已设置)。我的假设是否正确

我只是想避免LoadingPage,因为显示了三个屏幕:

  • 启动画面(应用启动时正确)
  • Lo​​adingPage(数据库迁移、http 请求、..)
  • BrowsePage 或 LoginPage

为了用户体验,最好只有两页。

我最终是这样的,但我相信有更好的方法:

protected override void OnStart()
{
  Page startPage = null;
  Task.Run(async() =>
  {
    await App.Database.Migrations();
    startPage = await CheckUser() ? new Layout.BrowsePage() : new LoginPage();
  }.Wait();
  this.MainPage = startPage();
}

【问题讨论】:

  • 您在寻找什么“更好的方法”?为什么你认为显示加载页面是一种低劣的用户体验?
  • 我想如果应用程序需要 5-8 秒来加载,那么加载页面就可以了。它向用户显示正在发生的事情(正在进行的迁移,...)。我测量了时间,启动应用程序需要 7 秒(三星 Galaxy A5)。

标签: c# multithreading xamarin xamarin.forms async-await


【解决方案1】:

好吧,您可以将所有内容放入 App 构造函数中,当您加载应用程序时,启动画面会显示更长的时间,但我实际上认为这是一个较差的解决方案。

先有一个启动画面,然后是一个加载页面,看起来与启动画面一模一样,但有一个进度条或加载图标,告诉用户它在做什么,这是一种更好的方法。

如果您必须在用户看到第一页之前执行此操作,那么加载屏幕是一个不错的选择,可以让用户知道为什么要花这么长时间。

我要添加的唯一另一件事是存储已加载的数据库的布尔值或版本号,因此您无需运行该迁移代码,除非您的应用版本增加。

通过这样做,您可以将此布尔检查放入您的 App 构造函数中,并立即加载第一页。如果需要迁移,则加载加载页面,让 OnStart 完成迁移,然后加载第一个应用屏幕。

【讨论】:

    【解决方案2】:

    另一种方法是将要同时运行的每个项目添加到任务列表中,然后等待所有项目。然后所有项目将异步运行,但您仍然可以获得 CheckUser 的结果。我不知道它是否比您使用的更好,但这是另一种方式。否则,如果您正在等待每个函数,则它们不会同时运行。

        protected async Task OnStart()
        {
            Page startPage = null;
            //create a list of the items you want to run concurrently
            List<Task> list = new List<Task>();
            list.Add(App.Database.Migrations());
            list.Add(CheckUser());
            //wait for all of them to complete
            Task.WaitAll(list.ToArray());
    
            //get the result from the CheckUser call
            Task<bool> checkUsertask = list[1] as Task<bool>;
            if (checkUsertask.Result == true)
                this.MainPage = new Layout.BrowsePage();
            else
                this.MainPage = new LoginPage();
        }
    

    如果您不喜欢列表[1],那么您可以在将其添加到列表之前创建一个任务,这样您就可以在完成后参考它。

    protected async Task OnStart()
    {
        Page startPage = null;
        //create a list of the items you want to run concurrently
        List<Task> list = new List<Task>();
        list.Add(App.Database.Migrations());
        var checkUserTask = CheckUser();
        //create this task directly so we can refer to it later to get the result
        list.Add(checkUserTask);
        //wait for all of them to complete
        Task.WaitAll(list.ToArray());
    
        //get the result from the CheckUser call
        if (checkUserTask.Result == true)
            this.MainPage = new Layout.BrowsePage();
        else
            this.MainPage = new LoginPage();
    }
    

    【讨论】:

    • 如果需要,OP 正在更新数据库,并然后从中检索用户信息。两者不能同时运行,一个依赖另一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多