Riga February 2016

Display ProgressBar while waiting for operation to complete

In my MVVMCross App I have an Android ProgressBar defined as:

<ProgressBar
    android:id="@+id/progressBar"
    style="?android:attr/progressBarStyleLarge"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:progressDrawable="@drawable/circular_progress_bar"
    android:gravity="right"
    local:MvxBind="Visibility Visibility(IsBusy)" />

In the ViewModel, the code executed when clicking the button to start the operation is like:

public void Next()
{
    IsBusy = true;

    try
    {
        //THE EXPENSIVE OPERATION
        var response = CallTimeConsumingService();

        if (response.MethodFailed)
        {
            _dialogService.DisplayAlert(this, response.Message);
            return;
        }

        ShowViewModel<ShowNextView>();
    }
    catch (Exception ex)
    {
        _dialogService.DisplayAlert(this, ex.Message);
    }

    IsBusy = false;
}

But the ProgressBar is not displayed unless I remove the last IsBusy = false;, but that means is just displayed when the Next() method hass exited (not while waiting)

What can I do to display the ProgressBar while waiting and disable it before navigating to the next page?

===EDIT====

Ended doing this:

public void Next()
{
   async () =>
       {
           IsBusy = true;
           await DoWork();
           IsBusy = false;
       });
}

adding the rest of the code to the DoWork with an await for the task

//THE EXPENSIVE OPERATION
var response = await CallTimeConsumingServiceReturningTask();

Answers


William Barbosa February 2016

This is happening because the process of updating the UI is currently happening in the same thread as your expensive operation. Until your operation is completed, the UI thread is blocked and the visual feedback is never shown properly. To solve this, you need to make your CallTimeConsumingService() into an async call (making it return a Task<T>) and await for it to complete.

If you have network calls in your method, the blocking methods have Async counterparts that are awaitable already. If your method just involves heavy processing, you should use TaskCompletionSource or Task.Run.


xleon February 2016

Previous answer is correct, but you can write a cleaner code by making the next() method async:

public async Task Next()
{
    IsBusy = true;

    try
    {
        //THE EXPENSIVE OPERATION
        var response = await CallTimeConsumingServiceReturningTask();

        if (response.MethodFailed)
        {
            _dialogService.DisplayAlert(this, response.Message);
            return;
        }

        ShowViewModel<ShowNextView>();
    }
    catch (Exception ex)
    {
        _dialogService.DisplayAlert(this, ex.Message);
    }

    IsBusy = false;
}

Post Status

Asked in February 2016
Viewed 1,534 times
Voted 10
Answered 2 times

Search




Leave an answer