Forum Xamarin.Forms

Correct way to cancel an async Task?

Lets say I have a search bar and a listView in a Content Page...
When I search for a text I run an async task that gets some info from a Rest Server.
But if I pop the page before the Task is completed I get an exception when it try to run something on MainThread.
A piece of the code:

        SearchBar searchBar = new SearchBar
                {
                    Placeholder = "Search",
                };

                searchBar.SearchButtonPressed += OnSearchBarButtonPressed;

                ListView listView = new ListView
                {
                    VerticalOptions = LayoutOptions.FillAndExpand,
                    RowHeight = 10,

                };

        async void OnSearchBarButtonPressed(object sender, EventArgs args)
            {

                SearchBar searchBar = (SearchBar)sender;
                string searchText = searchBar.Text;
                await Task.Run (async () => {
                    await GetInfo (searchText);

                });
            }

        private async Task GetInfo (string searchText)
        {

            searchList = await GetList (searchText);


            Device.BeginInvokeOnMainThread (async() => {

                        listView.ItemsSource = searchList;

            });
        }

        public static async Task<List<String>> GetList (string searchText)
        {

            //Get List throught Rest Server

            return searchList;
        }

To Cancel it I was trying to use a Cancelation Token...
I saw this topic and this tutorial and send a CancelationToken to my tasks as parameters and onDisapearing I called

          if (cts != null)
            {
                cts.Cancel();
            }

To Cancel the tasks but not sure if just passing the CancelationToken as an argument is enought and if Im doing right!

Any help?

Tagged:

Best Answer

Answers

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri BRMember ✭✭✭

    What I have tried to do so far... but didnt work..

        //define a new CacellationSource
        CancellationTokenSource cts;
    
    
        async void OnSearchBarButtonPressed(object sender, EventArgs args)
                {
                    cts = new CancellationTokenSource();
    
                    SearchBar searchBar = (SearchBar)sender;
                    string searchText = searchBar.Text;
    
    
    
                    try
                    {
                        await Task.Run (async () => {
                            try
                            {
                            await GetInfo (searchText, cts.Token);
                            }
                            catch (OperationCanceledException e)
                            {
                                Console.WriteLine("Cancel GetInfo ex {0}", e.Message);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine("ex {0}", e.Message);
                            }
    
    
                        }, cts.Token);
                    }
                    // *** If cancellation is requested, an OperationCanceledException results.
                    catch (OperationCanceledException e)
                    {
                        Console.WriteLine("Cancel ex {0}", e.Message);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("ex {0}", e.Message);
                    }
    
                    cts = null; 
                }
    
    
        private async Task GetInfo (string searchText, CancellationToken ct)
                {
    
                    try
                    {
                            searchList = await GetList (searchText, ct);
                    }
                    catch (OperationCanceledException e)
                    {
                        Console.WriteLine("Cancel GetList ex {0}", e.Message);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("ex {0}", e.Message);
                    }
    
    
    
                    Device.BeginInvokeOnMainThread (async() => {
                                listView.ItemsSource = searchList;
                    });
    
                }
    
        public static async Task<List<String>> GetList (string searchText, CancellationToken ct)
                {
    
                    //Get List throught Rest Server
    
                    return searchList;
                }
    
                protected override void OnDisappearing()
                {
                    base.OnDisappearing ();
                    if (cts != null)
                    {
                        cts.Cancel();
                    }
                }
    

    But it still hitting Device.BeginInvokeOnMainThread and Im getting an Exception

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri BRMember ✭✭✭

    Any Help?

  • SagarPanwalaSagarPanwala USMember ✭✭✭

    @DavidDancy : Is cancellation token abort the request or it still get the data from server?

  • DavidDancyDavidDancy AUMember ✭✭✭✭

    @SagarPanwala It depends. If you ignore the CancellationToken in your code, the token doesn't automatically throw an exception when cancellation is requested. Your code has to monitor the token's state and stop whatever it's doing if you see that the token's cancellation request has been triggered.

  • JafetGranados.3096JafetGranados.3096 USMember ✭✭
    edited September 2017

    @DavidDancy, What about TaskCanceledException? This class extends from OperationCanceledException but is not thrown when cancellationToken.ThrowIfCancellationRequested() is invoked, instead the TaskCanceledException is thrown. I have been reading about that, and the task.Status must be set to Canceled when that method is invoked. How can achieve that?

Sign In or Register to comment.