Reputation: 316
I am building an Android app through Xamarin/MonoTouch (so using C# rather than Java) and would like to display a ProgressBar while the app is communicating with the server. I have been attempting to do this using async, but I don't have a good understanding of how threading works, and I've been running into the same issue for the past few hours - the ProgressBar shows after my method call rather than before. My code is in the OnCreate() method, which I have also overridden to be async. Here it is:
loginButton.Click += async (sender, e) =>
{
progbar.Visibility = ViewStates.Visible;
var userFetcher = new UserFetcher();
var json = await userFetcher.FetchUserDetailsAsync(/*parameters*/);
//the above method is async and returns a Task<JsonValue>
ParseUserDetails(json); //another method I created
progbar.Visibility = ViewStates.Invisible;
//do some stuff using the parsed data
};
The issue I'm running into is that the FetchUserDetailsAsync seems to be blocking my thread. I have been testing this by shutting the server off so that it takes a long response time (but even when I test stuff like Thread.Sleep(5000) I have the same issue). After the method has been called, it runs both progbar.Visibility = ViewStates.Visible;
and progbar.Visibility = ViewStates.Invisible;
right after one another - I know this because when I comment out the Invisible part, the ProgressBar appears after my method got a "response" from the server. The compiler has also been giving me messages like "Skipped 67 frames! The application may be doing too much work on its main thread."
Like I said earlier, I'm not really experienced with threading, so it's very possible I'm just naively doing something wrong. Does anyone have a solution to this issue?
EDIT: Here is the source code for FetchUserDetailsAsync:
public async Task<JsonValue> FetchUserDetailsAsync(string url, string username, string password)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
request.ContentType = "application/json";
request.Method = "GET";
string myBasicHeader = AuthenticationHelper.MakeHeader(username, password);
request.Headers.Add("Authorization", "Basic " + myBasicHeader);
try
{
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
JsonValue jsonDoc = await Task.Run(() => JsonObject.Load(stream));
return jsonDoc;
}
}
}
catch (WebException e)
{
Console.WriteLine(e.ToString());
if (e.Status == WebExceptionStatus.ProtocolError)
{
var response = e.Response as HttpWebResponse;
if (response != null)
{
Console.WriteLine("HTTP Status Code: " + (int)response.StatusCode);
}
else
{
Console.WriteLine("No http status code available");
}
}
return null;
}
}
Upvotes: 1
Views: 2230
Reputation: 316
I figured out the issue. I was calling GetResponse()
instead of GetResponseAsync()
in my FetchUserDetailsAsync method.
Upvotes: 1
Reputation: 664
It looks like either FetchUserDetailsAsync or ParseUserDetails is blocking the UI thread. Because Task.Sleep(5000) is running synchronously. Try await Task.Delay(5000); in the line of FetchUserDetailsAsync to see if the progressbar show up. If it does, then you probably need to go into FetchUserDetailsAsync implementation to make sure it is implemented async
Upvotes: 1