在启动

时间:2017-09-15 17:08:02

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

我想接下来使用Xamarin执行:

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

  • 执行db迁移(如果有)(如果用户更新了应用并且第一次运行它)

  • 从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因为显示了三个屏幕:

  • 启动画面(启动应用程序时右侧)
  • LoadingPage(db migrations,http request,..)
  • 浏览页面或登录页面

对于用户体验,可取的只有两页。

我这样结束了,但我相信还有更好的方法:

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();
}

2 个答案:

答案 0 :(得分:1)

那么你可以把所有内容都放到App构造函数中,并且当你加载应用程序时,启动画面只显示更长时间,但我实际上相信这是一个较差的解决方案。

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

如果你必须在用户看到第一页之前这样做,那么加载屏幕是一个很好的选择,让用户知道为什么这么长时间。

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

通过执行此操作,您可以在App构造函数中放置此布尔检查,并立即加载第一页。如果需要迁移,请加载加载页面,让OnStart完成迁移,然后加载第一个应用程序屏幕。

答案 1 :(得分:0)

另一种方法是将要同时运行的每个项目添加到任务列表中,然后等待所有项目。然后所有项目都将运行异步,但您仍然可以获得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();
}