Flutter: lazy loading data from network with caching

Yury Chelomin
ProAndroidDev
Published in
3 min readMar 28, 2018

First off, I’m not a Flutter expert in any way, so many decisions illustrated here may be naive or inefficient or even plain ugly in eyes of true Flutter aficionado. However, we all started with something, so let’s get our hands dirty.

For the sake of exercise, let’s consider a very typical task of lazy loading a collection of data items from the network and displaying them in a list on the mobile device. Data can be fetched from the back end in ‘pages’ and that leads us for a few implications:

  1. If we need to display items #2 and #3 and they happen to belong to the same ‘page’, we certainly do not want to make two exact same network calls
  2. If we have fetched data for a particular item, displayed it and then this item goes out of view (or perhaps its Android view have been destroyed/recycled by a RecyclerView) and then in a short period of time we need to display it again, we don’t want to make another network call. Yes, that is we want to have some sort of caching.

Shall we start? Assume the backend API is as simple as just one endpoint for fetching a page of data:

That’s pretty trivial and the only interesting thing here is that the single method of our API is explicitly declared as asynchronous. Now let’s get a product and a page of products models that can inflate themselves out of response JSON:

... and …

So, now we have all the needful to retrieve data in pages, but should the rest of our app be aware of this concept? In most cases the answer is definite No, we’d rather have a layer of abstraction to get a product by index, and let this figure out wether or not a network call has to be made or we have some locally cached data available for immediate re-use. We’ll call this layer Repository; let’s first define interfaces for the Repository itself and I promise we are getting closer to something interesting, flutter-ish I’d say:

and Cache:

Now, define the logic for abstracting out pagination and caching. It’s pretty simple — whenever a product is requested by another part of the app, we lookup in cache, if it’s there, we just serve it. If it’s not there AND we have not requested the corresponding page from the backend, we do request it and return a Future to the client. And when a page of data gets back from the server, we complete all the pending Futures that can be resolved by that page. Sound complicated? Implementation shows that it’s as simple as promised:

We are all set to get a product that we need whenever we’d like to display it; but wait! Our repository returns not a product, but its future, so how are we supposed to render it on the screen? Perhaps, listen to its stream just like in the code above when waiting for the server response? That’s an option, but luckily we have even better option provided by Flutter, called FutureBuilder that abstracts all these details out for us:

Add salt and pepper and voila, here we go:

Of course, this is a quick-n-dirty solution. No error handling whatsoever. Some things could be done better. But hey, it works! The full code can be found here: https://github.com/chelomin/flute/tree/Medium_v1

Thanks and any feedback is welcomed and appreciated!

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Responses (9)

Write a response

what is the lifecycle of CachingRepository ? only when app is running ? if the user close and back after minutes, respository is gone ?

Hey, Yuri! Great job! Did you try KeepAlive widgets — https://docs.flutter.io/flutter/widgets/KeepAlive-class.html? Seems to be it`s apropriate mechanism for keeping widgets in cache.

You don’t use ListView.builder, so what will happen when you scroll over 1000 elements?