1

I am building an Android app with Xamarin that grabs data from Riot Games API and displays to the user. I want the HTTP request to be made in the background and update my UI, once it's done. I tried using ThreadPool.QueueUserWorkItem() but it executes the code below immediately and I want it to wait until it has grabbed the data. This is the code on my portable class library.

 public void GetSummonerInformation()
        {
            try
            {
                    HttpResponseMessage response = httpClient.GetAsync(url).Result;
                    response.EnsureSuccessStatusCode();
                    string result = response.Content.ReadAsStringAsync().Result;

                    var data = JsonConvert.DeserializeObject<Dictionary<string, App2.Models.SummonerDto>>(result);

                    var name1 = data.First().Value.name;
                    var id = data.First().Value.id;
                    var profileIconId1 = data.First().Value.profileIconId;
                    var revisionDate1 = data.First().Value.revisionDate;
                    sumId = id;
                    sumName1 = name1;
                    sumProfileIconId = profileIconId1;
                    sumRevisionDate = revisionDate1;
                    System.Diagnostics.Debug.WriteLine("{0} this is the  {1}", data.First().Value.name, data.First().Value.profileIconId);

            }catch(Exception ex)
            { System.Diagnostics.Debug.WriteLine(ex.Message); }

and this is my code on my Android mainactivity.cs

button2nd.Click += delegate
           {
                   //Runs the http request on a background thread so the application doesnt hang.Need to make the code after that to wait for the request to end and then exexute
                   //because it gives me a blank icon and i need to press the button again.
               ThreadPool.QueueUserWorkItem(o => mclass.GetSummonerInformation());
               System.Diagnostics.Debug.WriteLine(MyClass.sumProfileIconId);
               iconUrl = string.Format("http://ddragon.leagueoflegends.com/cdn/6.24.1/img/profileicon/" + MyClass.sumProfileIconId + ".png");
               DisplaySummonerIcon();
               DisplaySummonerInformation();
}

Thanks!

Henry
  • 2,953
  • 2
  • 21
  • 34

2 Answers2

0

Change:

ThreadPool.QueueUserWorkItem(o => mclass.GetSummonerInformation());

With:

await Task.Run(() => mclass.GetSummonerInformation());

And add 'async' keyword before 'delegate';

druy10
  • 26
  • 4
0

You're using asynchronous APIs (HttpClient), so you should use await:

public async Task GetSummonerInformationAsync()
{
  try
  {
    HttpResponseMessage response = await httpClient.GetAsync(url);
    response.EnsureSuccessStatusCode();
    string result = await response.Content.ReadAsStringAsync();
    var data = JsonConvert.DeserializeObject<Dictionary<string, App2.Models.SummonerDto>>(result);
    ...
    System.Diagnostics.Debug.WriteLine("{0} this is the  {1}", data.First().Value.name, data.First().Value.profileIconId);
  }
  catch(Exception ex)
  {
    System.Diagnostics.Debug.WriteLine(ex.Message);
  }
}

invoked as such:

button2nd.Click += async (_, __) =>
{
  await mclass.GetSummonerInformationAsync();
  System.Diagnostics.Debug.WriteLine(MyClass.sumProfileIconId);
  iconUrl = string.Format("http://ddragon.leagueoflegends.com/cdn/6.24.1/img/profileicon/" + MyClass.sumProfileIconId + ".png");
  DisplaySummonerIcon();
  DisplaySummonerInformation();
};

For more information about async and await, see my blog.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thank you for your answer!I used a background worker to achieve it in the end.Is there a benefit using your way? – Alex Tselikas Dec 18 '16 at 15:55
  • @AlexTselikas: Yes. 1) The code is clearer using `await` rather than a `Completed` event. 2) `await` doesn't waste a thread waiting for an HTTP download. – Stephen Cleary Dec 18 '16 at 18:01
  • But using await,my application skips frames. – Alex Tselikas Dec 22 '16 at 20:07
  • @AlexTselikas: `await` will not cause your application to skip frames. You must have a bug elsewhere. – Stephen Cleary Dec 22 '16 at 22:14
  • @StephenCleary i have similar use case. I am saving some data to DB in my webApi1, and use case is to also send this data to webApi2 if data saved successfully to DB. Now since client to webApi1 does not care about whether data to webApi2 was sent or not, i dont want to await my call to webApi2 within initial request from client to webApi1. I just want to return 201 to client and continue HttpPost to webApi2. I am wondering if doing Task.Run with polly is ok or I need a background service ? Thanks – kuldeep Sep 03 '21 at 13:55
  • 1
    @kuldeep: [You need a background service](https://blog.stephencleary.com/2021/01/asynchronous-messaging-1-basic-distributed-architecture.html). – Stephen Cleary Sep 03 '21 at 16:55
  • Thanks for the link, I would have preferred to use rabbitmq via masstransit, but in my use case i can not. But as i understood correctly, i think since i have the data in DB anyways (something like a durable queue point from your blog), all i have to do is just use background service to read this and send it via http post, and retry if for some reason http post fails. Additionally, i could use some timestamp at db level to be sure that this background service did the post successfully before the service actually got restarted. – kuldeep Sep 05 '21 at 04:21