Home > Software engineering >  Xamarin Forms - Wait for async method to complete before continuing
Xamarin Forms - Wait for async method to complete before continuing

Time:04-19

In my Xamarin.Forms application, I have code that opens a popup page (using the Rg Popups plugin) which executes a call to my API that inserts some data on the database. I need the async call for the popup to open to wait until the popup page's task finishes then execute another async call which updates a ListView in the current view.

However, the popup's async task does not wait until the popup has finished working to continue to the next task, which means the view isn't updated

Here's the code in question:

 bool jobTask = await CloseCurOpenJob();
                 
if (jobTask == true)
{
  await FillDocuments();
}
 await Navigation.PushPopupAsync(new JobClosePopupPage(Base.activeJobId));
 return true;

private async Task<string> FillDocuments()
        {
HttpClient client = new HttpClient();
            try
            {
                if (jobid > 0)
                {
                    var response = await client.GetStringAsync(myApiUri);
                    var DocumentsList = JsonConvert.DeserializeObject<List<DocumentHeader>>(response);
                    Documents = new ObservableCollection<DocumentHeader>((IEnumerable<DocumentHeader>)DocumentsList);

                    DocumentCount = Documents.Count();
                    DocumentSubtotal = Documents.Sum(instance => instance.TotalQuantity);
                }
               
                return "OK";
            }
            catch (Exception e)
            {
                return e.Message;
            }
}

And here's the code in the popup page's ViewModel

private async Task<bool> CloseJob(int jobid)
        {
            HttpClient client = new HttpClient();
            try
            {
                var response = await client.PostAsync(myAPIUri);
                string responseString = await response.Content.ReadAsStringAsync();
                if (response.IsSuccessStatusCode)
                {
                    await CheckGetOpenJob();
                    return true;
                }
                else
                {
                    await Application.Current.MainPage.DisplayAlert(Base.applicationTitle, responseString, "OK");
                    return false;
                }


              

            }
            catch (Exception e)
            {
                await Application.Current.MainPage.DisplayAlert(Base.applicationTitle, e.Message, "OK");
                return false;
            }
            finally
            {
                await Navigation.PopPopupAsync();
                
            }
        }

I have tried using Task.Run and Task.Delay but the result is still the same - the FillDocuments method runs after the popup has been shown, not after it has been dismissed.

CodePudding user response:

The Task.Wait() and Task.Result will make the program wait for the async task method competed.

If the CloseCurOpenJob() is like public async Task<bool> CloseCurOpenJob(){} You can try the following code:

// Both are applicable to simple Tasks:
bool jobTask = CloseCurOpenJob().Result;

or

Task<bool> result = CloseCurOpenJob();
result.Wait();
bool jobTask = result.Result;                 

According to your description, you want update the popup when it show. But you sayed that the popup will not show when you used the .Wait() method.

Generally speaking, it shouldn't happen. But you can try to use the Thread.Sleep() such as:

bool jobTask = await CloseCurOpenJob();
Thread.Sleep(1000); //make the thread to wait for 1s and the async task usually completes in 1s          
if (jobTask == true)
{
  await FillDocuments();
}

But this way seems not elegant, you can post the code about the CloseCurOpenJob() method. In addition, if the CloseCurOpenJob() is public async bool CloseCurOpenJob(), you can make the thread wait without the await. Such as

bool jobTask = CloseCurOpenJob();

CodePudding user response:

I wanted to share something I've figured out:

The problem was not in the code, but the flow of it. Namely, I needed one page to dismiss a popup while ANOTHER page was working.

The solution I think I found - it has not been tested - is as follows:

Show the popup Do the processing in the main page's thread after showing the popup - as it's asynchronous, the code will continue to the task. Dismiss the popup in the main page's code (using the PopAllPopup method of the Rg plugin).

So...

bool jobTask = await CloseCurOpenJob();
                 
    if (jobTask == true)
    {
      await FillDocuments();
    }

Would become

await Navigation.PushPopupAsync(new JobClosePopupPage(Base.activeJobId));
bool jobTask = MethodThatProcessesTheData().Result;
await Navigation.PopAllPopupAsync();

I think this is how it's supposed to go...

  • Related