Flutter Bookshelf App Part 3: Managing data the right way.

Norbert
ProAndroidDev
Published in
4 min readMar 6, 2018

--

“Binders and boxes on shelves in a large archive” by Samuel Zeller on Unsplash

In this post I’m am going to discuss a good way to store/ cache/ and load data. Most of today’s apps rely on a server to display information. In combination with a cache, a database and error handling, this can become pretty messy. Luckily there is a design pattern which makes accessing data very convenient and easy.

Without a pattern:

Before v3

Each screen needs data, and therefore requests the network to load it. Let’s say you also want to have a cache, now every screen first needs to check the cache and then the network. Everything added to the data layer is reflected inside UI code.

The code is tightly coupled and not well organized, the question arises why the screen manages the data.

Introducing the repository:

After v3

A repository is a datasource. To be more specific, to the rest of the app, it’s the only datasource. Screens requesting data don’t necessarily need to know where it is coming from. This allows all data related operations to be in one place. Refactoring and modifying becomes easy and accessing the data even easier.

Strucuture

  • The data folder contains all data related classes
  • I split pages (which are actual screens) and widgets (reusable screen elements) into their respective folders.

As always, the code can be found at: https://github.com/Norbert515/BookSearch/tree/v3

The repository

Same as the BookDatabase, the repository is a singleton.

These calls do not need any additional logic and are therefore simply delegated to the database.

This method returns all the books based on a search query. The result is composed of the books coming from the internet and the ones coming from the database (books which hold additional information such as the star and notes).

In v2 a database request was issued for every book. This is very inefficient for huge databases. This however involves only one SQL query:

  • First all books coming from the network are stored in a map (using the ID as its key)
  • Then all keys a queried together returning a list of books
  • These books hold more information, therefore we can simply replace the according network-book with the database-book

The list gets convert to “(“id1”, “id2”, …, “idn”)” and inserted into the SQLite query.

Error handling

You might have noticed the ParsedResponse class which is the return type of the method wrapped in a future.

This neat little generic class holds the already parsed response and the status code. This enables us to return a ready to use dart object alongside additional information such as the servers status code.

Now the search_book looks much cleaner. The data-flow is as follows:

  • Request the data
  • When it arrives check the status code and decide whether to show the result or an error message.

As an alternative to this, it is also possible to use a FutureBuilder which I will go into in one of my next posts.

Making as many widgets as dumb as possible

In v2 the BookCard managed it’s own clicks, meaning when pressed, it went right to the database and updated the appropriate entry. But there’s a better way.

Now, the BookCard exposes two on click listeners, one for the clickable star and one for the rest of the card surface. The card doesn’t know anything about a database or what so ever. It is now reusable in any part of the app.

Furthermore the logic is now at a more appropriate place, a simple card shouldn’t know about a database, its only purpose is to display data and notice clicks.

The Collection Screen

We have a centralized data access and made the BookCard reusable, let’s build a page which displays all starred books.

The repository exposes a method called getFavoriteBooks(), this method gets delegated to the database which then performs a rawQuery:

var result = await db.rawQuery('SELECT * FROM $tableName WHERE ${Book.db_star} = "1"');

I kept the loading indicator because at some point in time the books will also come from a remote database.

And that’s it, the collections page is done.

The build method is pretty much the same as the search screen one. The class can be found here.

Wrapping up

We learned:

  • how data abstraction can make the overall code more readable, and easier to manage.
  • how making widgets “dumb”, makes them easier to reuse and easier to debug.

If you liked the post be sure to hold that clap button down for a few second.

Also if you want the latest development updates you can follow me on Twitter.

Edit: Part 4 is now up!

--

--