Reputation: 477
I'm having an issue with MvvmCross on Xamarin.Android/iOS when I try to load the contents of an API endpoint during the initialization of a ViewModel. I'm loading the current weather forecast for an area from an API and I have it written in an async method and it is being called from on of the initialization lifecycle callbacks. So far I've tried Stat() and Init(). In both cases, my UI is loaded with the values from my ViewModel but then freezes immediately. If I set a breakpoint anywhere in the async code, the breakpoint catches and on playing through, it works as expected. I suspect some sort of a race condition somewhere but I'm unsure how to avoid it and get data to load when my ViewModel/View appears. Here's the code I have:
//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;
}
This async code works from a button press MvxCommand just fine; but if called from the constructor, Init, or Start it will freeze the UI every time if I don't have a breakpoint somewhere in there. If someone could help me find what I'm doing wrong I'd appreciate it. Thanks.
EDIT
I found that the app appears to run normally when I'm not debugging. I stop the debugger from Xamarin Studio and relaunch the app and it runs perfectly.
As requested here is my XML I'm using for binding FeelsLike:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="Text FeelsLike" />
I've also tried adding the .ConfigureAwait(false); to all of my await calls and it seems to be worse. The UI never gets initialized and it sits on a black screen rather than just my regular UI frozen.
This may be helpful, but here is a link to my project folder (it's very minimal since I'm just learning this framework): http://goo.gl/SJscZA
EDIT 2
The problem may be in my HttpClient code? I replaced it with a simple Task.Delay(5000) and returning an empty WeatherStatus to see what happened and it didn't freeze. I'll look into fetching data in another way. I'm new to Xamarin so I'm open to suggestions here. Thanks. Here is a snippet of my Task.Delay() code:
public async Task<WeatherStatus> GetWeatherStatus (string zip)
{
await Task.Delay (5000);
return new WeatherStatus ();
}
Upvotes: 3
Views: 2370
Reputation: 1062780
Usually, this means you need to add .ConfigureAwait(false)
to every await
, to prevent a deadlock in the sync-context:
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;
}
Upvotes: 5