DaveS
DaveS

Reputation: 61

How to use async/await correctly to display Xamarin Forms ActivityIndicator

I have code that gets executed when a ListView item is selected. Since this code can take a noticeable amount of time to execute I want to display an ActivityIndicator while it is running.

I have read through a lot of posts about the ActivityIndicator and I believe I have it setup correctly. I'm pretty sure my problem is due to the running code blocking the UI thread since the UI freezes completely during the process.

I've worked through every variation I have been able to find for using async/await with no luck so I'm assuming that I am still doing something incorrectly.

Here is my code:

private ListItem selectedList;
public ListItem SelectedList
{
    get
    {
        return selectedList;
    }
    set
    {
        if (selectedList != value)
        {
            var oldValue = selectedList;
            selectedList = value;
            buildThisList();
        }
    }
}

private async void buildThisList()
{
    StatusBarIsVisibile = true; 
    ThisList = Task.Run(async () =>
    {
        return await buildBnBList(SelectedList, selectedLocation, 
                         thisYearList.ListId)
                         .ConfigureAwait(false);
    }).Result;  // 1.8 seconds
    StatusBarIsVisibile = false;
    ThisList.MainVM = this;
    ThisList.BuildView();
    PIShowListHeaderText = SelectedList.Title.Trim();
}

private async Task<BnBList> buildBnBList(ListItem pSelectedList, State pselectedLocation, int pListId)
{
    BnBList newList = new BnBList(pSelectedList, pselectedLocation, pListId);
    List<BirdsnBflysMaster> bbfList = 
         App.BnBRepo.GetBirdsnBflys(selectedList.ListType); // 1.3 seconds
    Lists parentList = App.BnBRepo.GetAList(SelectedList.ListId); // .5 seconds
    BnBItem newBnBItem;
    foreach (BirdsnBflysMaster bbf in bbfList) // .4 seconds
    {
        newBnBItem = new BnBItem(parentList, bbf, selectedLocation, newList, thisYearList.ListId);
        newList.ListAll.Add(newBnBItem);
        if (newBnBItem.ListTypeID == "Bird")
        {
            ...
        }
        else
        {
            ...
        }
    }            
    return newList;
}

So:

How can I code this so that executing buildBnBList does not block the UI thread?

Upvotes: 2

Views: 1019

Answers (1)

Nkosi
Nkosi

Reputation: 247153

Yes you a mixing blocking (.Result) with async code which risks causing deadlocks. async void should be avoided, unless in an even handler.

So then why not do just that?

Create an event and event handler.

public event EventHandler ListSelected = delegate { }

this should now allow you to create an event handler

private async void OnListSelected(object sender, EventArgs e) {
    StatusBarIsVisibile = true; 
    ThisList = await buildBnBList(SelectedList, selectedLocation, thisYearList.ListId);

    StatusBarIsVisibile = false;
    ThisList.MainVM = this;
    ThisList.BuildView();
    PIShowListHeaderText = SelectedList.Title.Trim();
}

You would obviously subscribe to the event (early in the life-cycle of course)

this.ListSelected += OnListSelected;

and raise the event as needed

private ListItem selectedList;
public ListItem SelectedList {
    get {
        return selectedList;
    }
    set {
        if (selectedList != value) {
            var oldValue = selectedList;
            selectedList = value;
            OnListSelected(this, EventArgs.Empty);
        }
    }
}

Upvotes: 4

Related Questions