在初始化期间调用异步方法时,MvvmCross UI冻结

时间:2014-03-01 19:31:01

标签: c# android asynchronous xamarin mvvmcross

当我在ViewModel初始化期间尝试加载API端点的内容时,我在Xamarin.Android/iOS上遇到了MvvmCross的问题。我正在从API加载一个区域的当前天气预报,我用异步方法编写它,并从初始化生命周期回调中调用它。到目前为止,我已经尝试过Stat()和Init()。在这两种情况下,我的UI都加载了来自ViewModel的值,但随后立即冻结。如果我在异步代码中的任何地方设置断点,断点捕获并在播放时,它按预期工作。我怀疑某种情况下某种情况,但我不确定如何避免它并在我的ViewModel / View出现时加载数据。这是我的代码:

// WeatherService的

public async Task<WeatherStatus> GetWeatherStatus (string zip)
        {
            var client = new HttpClient();
            var msg = await client.GetAsync(string.Format(WeatherApiUrlBase, WeatherApiKey, zip));
            if (msg.IsSuccessStatusCode)
            {
                using (var stream = await msg.Content.ReadAsStreamAsync())
                {
                    using (var streamReader = new StreamReader(stream))
                    {
                        var str = await streamReader.ReadToEndAsync();
                        var obj = JsonConvert.DeserializeObject<WeatherStatus>(str);
                        return obj;
                    }
                }
            }
            return null;
        }

// FirstViewModel

public async override void Start ()
{
    base.Start ();
    FetchWeatherStatus ();
}

private async void FetchWeatherStatus() {
    var weatherData = await _service.GetWeatherStatus ("84043");
    FeelsLike = weatherData.current_observation.feelslike_f;
}

这个异步代码可以通过按下按钮MvxCommand就好了;但是如果从构造函数,Init或Start它调用,每次如果我在那里没有断点那么会冻结UI。如果有人能帮助我找到我做错的事情,我会很感激。感谢。

修改

我发现当我没有调试时,应用程序似乎正常运行。我从Xamarin Studio停止调试器并重新启动应用程序,它运行完美。

这里要求的是我用于绑定FeelsLike的XML:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    local:MvxBind="Text FeelsLike" />

我也试过添加.ConfigureAwait(false);我所有的等待电话,似乎更糟。 UI永远不会被初始化,它位于黑屏上,而不仅仅是我的常规UI冻结。

这可能会有所帮助,但这里有一个指向我的项目文件夹的链接(因为我刚刚学习这个框架,所以它非常小): http://goo.gl/SJscZA

编辑2

问题可能出在我的HttpClient代码中?我用一个简单的Task.Delay(5000)替换它并返回一个空的WeatherStatus以查看发生了什么并且它没有冻结。我将研究以另一种方式获取数据。我是Xamarin的新手,所以我愿意接受这里的建议。谢谢。这是我的Task.Delay()代码的片段:

public async Task<WeatherStatus> GetWeatherStatus (string zip)
    {
        await Task.Delay (5000);
        return new WeatherStatus ();
    }

1 个答案:

答案 0 :(得分:3)

通常,这意味着您需要为每个.ConfigureAwait(false)添加await,以防止同步上下文出现死锁:

    public async Task<WeatherStatus> GetWeatherStatus (string zip)
    {
        var client = new HttpClient();
        var msg = await client.GetAsync(string.Format(WeatherApiUrlBase, WeatherApiKey, zip)).ConfigureAwait(false);
        if (msg.IsSuccessStatusCode)
        {
            using (var stream = await msg.Content.ReadAsStreamAsync().ConfigureAwait(false))
            {
                using (var streamReader = new StreamReader(stream))
                {
                    var str = await streamReader.ReadToEndAsync().ConfigureAwait(false);
                    var obj = JsonConvert.DeserializeObject<WeatherStatus>(str);
                    return obj;
                }
            }
        }
        return null;
    }