Fetching data from REST API and MVVM model

rozman50rozman50 Member ✭✭

I made a Connection class, where I have everything related to connection to REST API, including URL, generic methods and it's working as intended.

Then I have LocationPage, where locations are displayed. I'm creating those location elements in code behind (LocationPage.xaml.cs) and putting them into grid.

Now the problem comes, since it takes some time for data to get fetched from API, it breaks my app with exception: "Object referenced or not null" (something in those lines).

I'm setting BindingContext to LocationViewModel

LocationPage.xaml.cs

        public partial class LocationPage : ContentPage
        {
            private LocationViewModel lvm;

            public LocationPage ()
            {
                InitializeComponent ();
                BindingContext = lvm = new LocationViewModel();
            }

LocationViewModel.cs

        public LocationViewModel()
                {
                    LoadLocationsAsync();
                }

                public async Task LoadLocationsAsync()
                {
            // going to connection class which return list of locations
                    _locations = await Connection.GetAllAsync<Location>("location");

                }
   private IList<Location> _locations;
    public IList<Location> Locations
            {
                get { return _locations; }
                set {
                    _locations = value;
                    OnPropertyChanged();
                }
            }

My question is. What is the correct way of loading async data in MVVM from REST API, And how to tell LocationPage.xaml.cs to wait until data is fetched in LocationViewModel AND only then it should start constructing elements in LocationPage codebehind and showing them on page, maybe even showing a spinner.

Thank you all!

Tagged:

Answers

  • JohnHardmanJohnHardman GBUniversity mod

    @rozman50 said:
    My question is. What is the correct way of loading async data in MVVM from REST API, And how to tell LocationPage.xaml.cs to wait until data is fetched in LocationViewModel AND only then it should start constructing elements in LocationPage codebehind and showing them on page, maybe even showing a spinner.

    Without having your XAML available to check, I would assume that your LocationPage.xaml is binding to LocationViewModel's Locations property. That will result in a Null Reference Exception as Locations will be null until Connection.GetAllAsync<Location>("location"); has completed and _locations has been set to a non-null value.

    As to the "correct" way of loading async data in MVVM from a REST API, there are multiple correct answers. I prefer to do one of two things depending on scenario. Either, (a) get the data before pushing the page that will display the data, or (b) initially display the page without data but with an ActivityIndicator or similar, initiate the async request for data, then when the data is available populate the data on the page and remove the ActivityIndicator. In either case, manage cancellation tokens, to that the async request can be cancelled if the user hits the back button etc.

  • rozman50rozman50 Member ✭✭

    Yes, I'm binding to LocationViewModel in LocationPage.xaml.cs (code is available in first post). I understand that LocationPage is trying to access Locations list, which is empty, but I don't know how to prevent it from accessing it, before the Connection.GetAllAsync<Location>("location"); has finished getting data and therefore crashing my app.

  • JohnHJohnH GBMember ✭✭✭✭✭

    @rozman50 said:
    Yes, I'm binding to LocationViewModel in LocationPage.xaml.cs (code is available in first post). I understand that LocationPage is trying to access Locations list, which is empty, but I don't know how to prevent it from accessing it, before the Connection.GetAllAsync<Location>("location"); has finished getting data and therefore crashing my app.

    It isn't an empty list, it is null.

  • batmacibatmaci DEMember ✭✭✭✭✭
    You probably have a deadlock. You shouldn't call async function syncronously like that. You should use onappearing method to call it with async await. I would advise you to use mvvm library like freshmvvm which will make you async await work easier. Freshmvvm has viewappearing function can be async. You can use this one or init function as async but not constructor
  • rozman50rozman50 Member ✭✭

    I managed to make it work with Task.Run(async () => { await Initialize(); }).Wait(); from this thread: search "Calling Asynchronous method from ViewModel Constructor Xamarin.Forms" on google and it will be first result from stackoverflow (I can't post links yet)

    Also thanks @batmaci, will look into this framework and @JohnHardman

  • NMackayNMackay GBInsider, University mod

    There are other frameworks, I'd recommend Prism, 7.2 especially makes this all very simple.

  • rozman50rozman50 Member ✭✭

    @NMackay I read on the internet about Prism, but many people say, that it's only worth it, if you are making a big project. Should I, as a total newbie start using it in very small and simple project, just for the sake of learning it, or would it be better to start with other, smaller and maybe simpler frameworks like freshmvvm?

  • JohnHardmanJohnHardman GBUniversity mod
    edited June 24

    @batmaci said:
    You probably have a deadlock.

    @rozman50 said:
    I managed to make it work with Task.Run(async () => { await Initialize(); }).Wait(); from this thread: search "Calling Asynchronous method from ViewModel Constructor Xamarin.Forms" on google and it will be first result from stackoverflow (I can't post links yet)

    The code in your original post will not have a deadlock. As both myself and @JohnH said above, you were getting a Null Reference Exception because Locations was null, not empty.

    However, as @AdamP warned in the StackOverflow thread that you referred to, the pattern that you have now followed in changing your code may cause a deadlock in some scenarios.

  • NMackayNMackay GBInsider, University mod

    @rozman50 said:
    @NMackay I read on the internet about Prism, but many people say, that it's only worth it, if you are making a big project. Should I, as a total newbie start using it in very small and simple project, just for the sake of learning it, or would it be better to start with other, smaller and maybe simpler frameworks like freshmvvm?

    For small simple projects, MVVM Light is a good place to start but it's worth learning how binding works etc and then pick a framework that suits your needs. People saying Prism is only good for large projects aren't correct though, it leans itself well to large projects as it's the only MVVM Framework that supports modularisation. It's also probably the best supported.

    Pick what meets your needs best though, the framework should make your left easier. They also help you keep right judging by the some of the hand rolled disasters I've had to work on.

Sign In or Register to comment.