在异步方法完成之前,UI不会更新

时间:2017-03-16 14:37:43

标签: c# xamarin xamarin.forms async-await ui-thread

在我的项目中,我想显示进度指示器,从Web服务检索数据并隐藏进度指示器。如果我这样做,我目前必须等到我从webservice检索数据,然后立即更新带有结果的UI。但进度指标从未出现过。所以看来,我在UI线程上工作或阻塞。但在哪里?

这是我的代码的简单版本:

SomePage的

LoadData()

SomeView

Response headers (165 B)    
    Host    
    "localhost:8000"
    [Learn More]
    Connection  
    "close"
    [Learn More]
    Content-Type    
    "text/html; charset=UTF-8"
    [Learn More]
    Date    
    "Thu, 16 Mar 2017 14:33:53 GMT"
    [Learn More]
    Transfer-Encoding   
    "chunked"

我尝试了不同的东西,我在UI和后台线程之间失去了同步。例如。在public function login(Request $request){ return response()->json([ 'name' => 'Abigail', 'state' => 'CA' ]); } 完成之前调用了.

有人可以给我一个关于这里有什么问题的提示吗?

3 个答案:

答案 0 :(得分:1)

我不完全确定为什么你的代码按照它的方式行事,但是你应该考虑到Device.BeginInvokeOnMainThread()没有给出关于何时执行动作的任何承诺。在内部,它执行以下操作:

// Simplified
s_handler = new Handler(Looper.MainLooper);
s_handler.Post(action);

它将您的操作传递给消息队列,然后在将来的未知时间点执行操作。

但是,我建议您重新考虑应用程序的体系结构。通过利用MVVM模式和数据绑定,您可以非常轻松地控制进度指示器的可见性。

在ViewModel中,您将拥有以下内容:

private bool isBusy;

public bool IsBusy() {
    get { return isBusy; }
    set { SetProperty(ref isBusy, value); }
}

在具有上述ViewModel作为其BindingContext的视图中,您将具有以下内容:

<ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}" />

现在,无论何时开始长时间运行操作,只需将isBusy更改为true,View就会自动显示由于绑定而运行的ActivityIndi​​cator。

答案 1 :(得分:0)

我不熟悉xamarin.forms,所以以下内容可能完全是垃圾。如果是这样,请告诉我,我会删除答案。

对我来说,似乎你有一个带有事件处理程序OnItemSelected的Form,它应该显示一个DetailView,这是另一种形式。创建DetailView对象后,您要加载详细信息视图。这种加载需要一些时间,同时您希望通知操作员表单正在加载。

我不确定您希望获得视觉反馈的位置:在SomePage或SomeView上。答案并不重要,除了显示和隐藏视觉反馈的命令最好写在显示反馈的类中。

在SomeView上显示反馈

在这种情况下,SomeView可以显示和隐藏视觉反馈,例如进度条或ajax加载器。代码就像:

由于我熟悉表格,我会把它写成表格。你的代码非常相似

process

或者如果你真的需要在开始获取数据前等待5秒钟:

class SomeView : Form
{
    void ShowVisualFeedBack()
    {
        ...
    }
    void HideVisualFeedBack()
    {
        ...
    }

    public async Task LoadDataAsync()
    {
        bool result = false;
        this.ShowVisualFeedBack()
        try
        {
            this.itemList = await WebService.Instance.GetData();
            result = true;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
        this.HideVisualFeedBack();
        return result;
    }
}

在SomePage上显示反馈

 try
 {
      await Task.Delay(TimeSpan.FromSeconds(5));
      this.itemList = await WebService.Instance.GetData();
      result = true;
  }

顺便说一下,当您的主题正在等待GetData()时,它无法更新您的视觉反馈。一些像GIF这样的视觉反馈方法不需要你的线程更新,但如果你有类似进度条的东西,你的线程需要更新它。您可以通过等待GetData完成之前的最长时间,更新进度并再次等待

来完成此操作
 class SomePage : Form
{
    void ShowVisualFeedBack()
    {
        ...
    }
    void HideVisualFeedBack()
    {
        ...
    }

    private async Task ShowDetailView()
    {
        this.ShowVisualFeedBack();
        this.DetailView = new MyView();
        await view.LoadContent();
        this.HideVisualFeedBack();
     }
}

答案 2 :(得分:0)

非常愚蠢的错误。我有这样的事情:

private async Task ShowDetailView()
{
    var view = new MyView();
    this.detailView = view;
    await view.LoadContent();
    this.mainGrid.Children.Add(this.detailView);
}

当然,他等待操作完成,然后显示结果。这是正确的方法:

private async Task ShowDetailView()
{
    var view = new MyView();
    this.detailView = view;
    this.mainGrid.Children.Add(this.detailView);
    await view.LoadContent();
}

我应该删除我的问题吗?也许,因为有时候你会想念树林。