Forum Xamarin.Forms

Always use Task.Run() for the best User Experience.

I'm using this rather abrasive statement as a sort of hypotheses. Please do not take offense to this title. I merely used this as a means of grabbing attention and starting a discussion.

This discussion is furthered from the following thread:
https://forums.xamarin.com/discussion/139992/calling-async-methods-from-main-thread-is-a-bad-idea?

I will now try to explain the case.

Consider the following code taken directly from the thread in the link above:

protected override async void OnResume()
{
    //show preloader

    var result = await SlowAsync(); //blocks UI
    //---versus---
    var task = SlowAsync();
    var result = await task; //also blocks UI
    //---versus---
    var result = await Task.Run(async ()=> await SlowAsync()); //does not block UI

    //update UI, hide preloader
}

public async Task<bool> SlowAsync()
{
    FindPrimeNumber(100000); //or whatever sync, usually not that CPU-heavy, but still blocking the UI for some precious milliseconds (some conditions, sorting some lists, anything)

    await Task.Delay(10); //or whatever async, some server fetch, this is not blocking the UI, the main thread is released until it is finished .. unless it also contains some synchronous code

    return true;
}

The OnResume() method in this code should give a fair example of the problem:
async methods will block the main thread until the point where a new thread is started.

More descriptively:
When a slow, async method is called from a lifecycle method or a command, it will run entirely on the main thread, even if it is marked as async. On Android, this causes the entire application to freeze. To the detriment of the user experience.

You can force a release of the main thread by starting all these methods with await Task.Run(). Animations will play normally on Android and the application wont freeze.

In the application I'm working on with my team I implemented this and it improved the user experience on Android immensely.

So my possibly-controversial statement is:
Start your lifecycle methods and Commands with await Task.Run() and only use the main thread when necessary using Xamarin.Essential's MainThread.InvokeOnMainThreadAsync() method.

Please discuss whether you agree with this statement or not and whether it should be included in the documentation or in Xamarin's internal code.

On a lighter note: Please also critique my writing. I am a junior developer and this is the first time I've collected the courage to write something semi-professional for others to discuss. Any feedback is appreciated :smile:

Posts

  • JohnHardmanJohnHardman GBUniversity admin
    edited February 22

    @LittleBearAndChicken

    You might want to look at the RunSafe method in
    https://github.com/xamarin/Sport/blob/master/Sport.Mobile.Shared/ViewModels/BaseViewModel.cs

    I use something similar, although changed to meet my particular needs. The Xamarin Sports app is old, but still contains some useful techniques that you might want to use yourself or adapt to your needs.

    You referenced the thread at https://forums.xamarin.com/discussion/139992/calling-async-methods-from-main-thread-is-a-bad-idea?
    I haven't re-read that all the way through, but I stand by the comment that I made (long ago) in that thread about using await in lifecycle methods. It can result in race conditions and so is normally best avoided.

    @LittleBearAndChicken said:
    On a lighter note: Please also critique my writing.

    You've picked a subject that can be difficult to explain in a short forum post. Xamarin.University used to run entire classes on async/await (I seem to recall that there were three related ones). In keeping things short, I find some of what you said misleading, particularly when talking about async methods that do synchronous work before doing something genuinely asynchronous. I think most people would consider doing significant synchronous work on the calling thread of a method marked async to be poor practice (if it's a private method where you control how it's used, it might not be ok - depends on scenario). That doesn't mean that people don't do it though, and Task.Run (particularly via a method such as RunSafe) can be used to protect against that, as well as having other benefits.

    @LittleBearAndChicken said:
    On a lighter note: Please also critique my writing. I am a junior developer and this is the first time I've collected the courage to write something semi-professional for others to discuss. Any feedback is appreciated :smile:

    Keep at it. Putting yourself out there is a great way to learn. It's one reason that I answer posts in these forums - to see if anybody disagrees with what I post and to see if anybody posts anything that I can learn from. Thinking about other people's questions in itself can make you think about things that wouldn't have occurred to you otherwise. Stick with it.

    (unfortunately these forums are being closed soon, to be replaced by Microsoft Q&A. I find that a much more restrictive environment, and not as conducive to building a long-term repository of searchable answers. I suspect that I will be answering far fewer questions there than I have here, unless Microsoft Q&A is itself improved)

  • @JohnHardman
    Thank you for your response!

    I never knew about that Xamarin project and upon re-reading the thread I focused more about what you had to say about race conditions in life cycle methods. I never thought about that, interesting. Even though personally we have never encountered problems like this but then again, we use OnAppearing() and very little else. I definitely have some more research to do about backgrounding.

    I wonder if there is an example project that shows OS specific implementationss for backgrounding like you mentioned in that thread. I don't know if that's still relevant given that the discussion was 2 years ago but that definitely would be interesting.

    By the way thank you for the positivity at the end of your reply. It's greatly appreciated :)

  • JohnHardmanJohnHardman GBUniversity admin

    @LittleBearAndChicken said:
    I wonder if there is an example project that shows OS specific implementationss for backgrounding like you mentioned in that thread. I don't know if that's still relevant given that the discussion was 2 years ago but that definitely would be interesting.

    For backgrounding, I'm not aware of any comprehensive samples. As a starting point, I suggest https://www.xamarinhelp.com/xamarin-background-tasks/ and the Xamarin University archive at https://github.com/XamarinUniversity/AllCourseExercises (look for AND210 and IOS210). Those are all old sources though.

Sign In or Register to comment.