0

I have xamarin.forms app contains a listview which will load values from Rest API.Which is working fine.I have button just above the listview.When I click on the button, the listview API call will be placed again and the listview should update. But stuck at this update part.I am not using MVVM pattern.The listview listing portion is an async Task.I am calling the async task again when the button click, but App gets crash. Is it due to calling the async task again from button click? Any help is appreciated.

Here is My code.

 namespace app
    {
        public partial class List : ContentPage
        {   
            PendingWeekRange pendingWeekRange = new PendingWeekRange();
            public TimeSheetList()
            {
                InitializeComponent();        
                Task.Run(async () =>
                {
                    await LoadScreenItems();
                });           
            }    
            async Task LoadScreenItems()
            {
               await Task.Run(async () => {               
                    try
                    {                 
                          // Doing some stuff

                            await loadTimeSheetList();               
                    }
                    catch (Exception)
                    {

                    }
                });
            }  
            async Task loadTimeSheetList()
            {
                await Task.Run(() => {  +  string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
                APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);       
                    try
                    {                                        
                        List<ListData> resultObjForPendingTimeSheetList = callForAPICallResult<List<ListData>>();
                        if (resultObjForPendingTimeSheetList != null)
                        {

                            TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
                            screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
                            TimesheetList.IsVisible = true;
                        }
                        else
                        {

                        }
                    }
                    catch (Exception)
                    {                    
                    }
                });          
            }
         async   void Button_Tapped(object sender, EventArgs e)
            {
                try
                {            
                      // Calling my listview again. After calling app gets crash                
                  Task.Run(async () => await loadTimeSheetList());                           
                }
                catch (Exception ex) { }
            } 
        }
    }
Anand
  • 1,866
  • 3
  • 26
  • 49
  • Update your code with this and check. async void Button_Tapped(object sender, EventArgs e) { try { // Calling my listview again. After calling app gets crash await loadTimeSheetList(); } catch (Exception ex) { } } – Krunal Bagadia Jun 27 '19 at 05:34
  • @KrunalBagadia Hi, I tried that still no luck – Anand Jun 27 '19 at 05:37
  • @AndroDevil Is your `APICallResult` a task type method? If so, why not call it like `await callForPendingTimeSheetList.APICallResult>();` directly? – Ax1le Jun 27 '19 at 09:20
  • @LandLu-MSFT Bro I edited my code. "APICALL" is another class which makes API call – Anand Jun 27 '19 at 10:00
  • @AndroDevil Still can't figure out what your APICall looks like. Try to test it with a const fake list data, would it still crash? – Ax1le Jun 27 '19 at 10:13
  • @LandLu-MSFT I removed the await Task.run, Then it will work fine – Anand Jun 27 '19 at 11:25
  • @LandLu-MSFT Bro If I call a async method again like this will it cause preoblems?because when this page loads firstly that async method will call.After I click the button, It will again call it.At that time app will crash – Anand Jun 27 '19 at 11:27
  • @AndroDevil I don't think it will cause problems. But you utilized too much `Task.Run` and some of them can be removed. Please optimize your code. – Ax1le Jun 28 '19 at 01:36

2 Answers2

1

A few things before getting to the problem. You've got async/await all wrong, go though Async Programming

Task.Run runs the passed action on a different thread, if you make changes to UI elements on this thread, your app will definitely(take my word) crash.

If you want to make async call at page launch, make use of OnAppearing method (if you only want to call once, maintain a flag)

Do not change the ItemsSource of a list view frequently, just clear and add items to it.

namespace app
{
    public partial class List : ContentPage
    {   
        PendingWeekRange pendingWeekRange = new PendingWeekRange();

        private ObservableCollection<ListData> TimesheetObservableCollection = new ObservableCollection<ListData>();
        public TimeSheetList()
        {
            InitializeComponent();          
            TimesheetList.ItemsSource = TimesheetObservableCollection;
        }
        protected override async OnAppearing()
        {
            // flag for first launch?
            await LoadScreenItems();

        }
        async Task LoadScreenItems()
        {     
            try
            {                 
                    // Doing some stuff
                    TimesheetObservableCollection.Clear();
                    TimesheetObservableCollection.AddRange(await GetTimeSheetList());
            }
            catch (Exception)
            {
                //handle exception
            }
        }  
        async Task<List<ListData>> GetTimeSheetList()
        {
            string postdataForPendingList = "{\"date\":\"" + "1" + "\"}";
            APICall callForAPICallResult = new APICall("/API/ListMobile/ListForApproval", postdataForList, loadingIndicator);       
            try
            {                                        
                return callForAPICallResult<List<ListData>>();
            }
            catch (Exception) 
            { 
                // handle exception
            }        
        }
        async void Button_Tapped(object sender, EventArgs e)
        {
            try
            {
                // Calling my listview again. After calling app gets crash                
                TimesheetObservableCollection.Clear();
                TimesheetObservableCollection.AddRange(await GetTimeSheetList());
            }
            catch (Exception ex) { }
        } 
    }
}
memsranga
  • 1,088
  • 7
  • 13
0

@Androdevil,

Update your loadTimeSheetList with this,

async Task loadTimeSheetList()
    {

            try
            {            
                // I am calling my API for Listview here.            
                List<TimeSheetListData> resultObjForPendingTimeSheetList = await callForPendingTimeSheetList.APICallResult<List<TimeSheetListData>>();
                if (resultObjForPendingTimeSheetList != null)
                {

                    TimesheetList.ItemsSource = resultObjForPendingTimeSheetList;
                    screenStackLayout.VerticalOptions = LayoutOptions.FillAndExpand;
                    TimesheetList.IsVisible = true;
                }
                else
                {

                }
            }
            catch (Exception)
            {                    
            }

    }
Krunal Bagadia
  • 419
  • 2
  • 8