Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Hands-On Android UI Development

You're reading from  Hands-On Android UI Development

Product type Book
Published in Nov 2017
Publisher Packt
ISBN-13 9781788475051
Pages 348 pages
Edition 1st Edition
Languages
Author (1):
Jason Morris Jason Morris
Profile icon Jason Morris

Table of Contents (21) Chapters

Title Page
Credits
About the Author
About the Reviewers
www.PacktPub.com
Customer Feedback
Preface
Creating Android Layouts Designing Form Screens Taking Actions Composing User Interfaces Binding Data to Widgets Storing and Retrieving Data Creating Overview Screens Designing Material Layouts Navigating Effectively Making Overviews Even Better Polishing Your Design Customizing Widgets and Layouts Activity Lifecycle
Test Your Knowledge Answers

Chapter 6. Storing and Retrieving Data

Data storage might not, at first glance, seem to be at all related to a user interface, but in the majority of applications, the user interface exists to manipulate long-lived data both on the device and on the network. This means that while it does not directly influence the look of the application, it does influence the user experience. Users expect the application to always reflect the latest data available to them, as we explored in Chapter 5, Binding Data to Widgets. Applications written using a reactive pattern ensure that the user interface is always up to date with the latest data available to the application, and the Android data binding system helps to make writing reactive applications easy. Even without the data binding framework, Android itself has always been built for reactive applications from the very bottom layers upward, but until recently, this behavior required huge amounts of boilerplate code.

When you develop any sort of application...

Data storage in Android


Almost every application needs to store data persistently at some point. Any data that needs to remain intact when your application is stopped must be placed in some kind of data storage system where you can retrieve it again later. You can store all the data on the server, but then your application will only function when the user has an active internet connection and will only ever be as fast as their available connection. You can also store data as files on the device's local filesystem, but this means you need to either load all the data into memory and save the whole application state every time it changes, or you need to write complicated logic to maintain integrity between the various files your application will write.

The Android ecosystem has a large number of database systems available, the most popular of which is probably SQLite. Data can be saved in SQLite tables and retrieved through structured queries. This provides an ideal way to store all of your...

Using the SQLite database


SQLite is an excellent little SQL compatible database that is embedded into the core Android system. This allows you to leverage a complete SQL database without having to ship one with your application (which will raise your code size dramatically). This makes it the most common tool for storing structured data on Android, but it's by no means the only option.

For many applications that require real-time synchronization with a server, people use Firebase Database. Firebase is a Google cloud product that includes a powerful document database that synchronizes its data in real time, all the way to the client. This means that an event is triggered on a client when any of its data is modified from outside, making it suitable for chat and messaging applications. However, tools such as Firebase require a large additional client-side API, tie your application to a service, and are very difficult to port your application away for later. Applications built with them may also...

Introducing Room


Direct use of SQLite requires a huge amount of code dedicated to converting the SQLite structured data into Java objects, and then preparing SQL statements to store those objects back into the database. Mapping an SQL record to a Java object normally takes the following form:

public Attachment selectById(final long id) {
   final Cursor cursor = db.query(
           "attachments",
           new String[]{"file", "type"},
           "_id=?",
           new String[]{Long.toString(id)},
           null, null, null);

   try {
       if (cursor.moveToFirst()) {
           return new Attachment(
                   new File(cursor.getString(0)),
                   Attachment.Type.valueOf(cursor.getString(1))
           );
       }
   } finally {
       cursor.close();
   }
   return null;
}

As you can immediately see, there's a lot of code there that you will need to repeat again and again for every one of your data-model objects.

Fortunately, Google has produced a solution to this...

Creating an Entity model


Room, much like an SQL database, is optionally asymmetric; what you write to it might not be in the exact same format as what you read from it. When you write to a Room database, you save Entity objects, but when you read, you can read virtually any Java object. This allows you to define object models that best suit your user interface, and load them with JOIN queries rather than resorting to one or more additional queries for each object you wish to present to the user. While JOIN queries might be overly expensive on a server, on a mobile device they are often significantly faster than a multiquery alternative. As such, when defining an entity model, it's worth considering what you will need to save in your database as well as what specific fields you will need on your user interface. The data you need to write to storage becomes your entity, while the fields on your user interface become fields in Java objects that can be queried through Room.

An Entity class in...

Creating the Data Access Layer


Now that you have something to write into the database, you need some way to actually write it, and a way to retrieve it again. The most common pattern is to have a dedicated class to deal with this for each class--a Data Access Object class, also known as a DAO. In Room, however, all you have to do is declare what they should look like using an interface; Room will write the implementation code for you. You define your queries using the @Query annotation on a method, like this:

@Query(“SELECT * FROM users WHERE _id = :id”)
public User selectById(long id);

This has a huge advantage over traditional O/R mapping layers in that you can still write any form of SQL query, and let Room figure out how to convert it into the object model you ask for. If it can't write the code, you get an error at compile time, rather than potentially having your app crash for your users. This also has an additional advantage: Room can bind your SQL queries to non-entity classes, allowing...

Creating a database


When writing an application using Room, you'll need to define at least one Database class. Each of these corresponds to a specific database schema--a collection of Entity classes and the various ways in which they can be saved, and loaded from storage. It may also serve as a convenient place to write other database-related logic for your application. For example, the ClaimItem and Attachment classes need to save and load various types that Room will not understand; for example, Date, File, the Category enum, and AttachmentType enum. Each of these classes will need a TypeConverter method that can be used to convert it to and from primitives that are understood by Room.

Room Database classes are abstract. This is because they are extended by the Room annotation processor to produce the implementation you'll use at runtime. This allows you to define any number of concrete method implementations in a database class that might be useful for your application. Follow these steps...

Accessing your Room database


So far, you've built all the components for a Room managed SQLite database, but you still don't actually have access to it. You can't instantiate the ClaimDatabase class directly because it's abstract, and you have the same problem with the DAO interfaces, so what's the best way to access the database? Room provides you with an entry class that will correctly instantiate the generated ClaimDatabase implementation, but that isn't the whole story; your entire application relies on this database, and it should be set up when the application starts and should be accessible by the entire application.

You can use a singleton ClaimDatabase object, but then where will the SQLite database file be placed? In order for it to be stored in your application's private space, you need a Context object. Enter the Application class, which when used, holds the first onCreate method that will be invoked in your application. Follow these quick steps to build a simple Application class...

Test your knowledge


  1. The Room API for Android provides which of the following?
    • A complete database solution
    • A lightweight API on top of SQLite
    • An object storage engine
  2. Returning LiveData from a Room DAO requires that you do which of these?
    • You observe it for changes in order to retrieve data
    • You run the query on the main thread
    • You call the query method again when notified by the LiveData object
  1. Database queries that don't return LiveData should do what?
    • Be avoided
    • Be run on a worker thread
    • Return Cursor objects
  2. Writing an update method for Room requires which of the listed?
    • An @Query(“UPDATE method on a DAO interface
    • An @Update method taking an Entity object on an interface
    • Will be added to your Entity implementations

Summary


The way you store and retrieve structured data in an Android application has a direct knock-on-effect on how your user will experience your application. When you choose to use a system like Room, CouchDB, or Firebase, where data changes are pushed through the application as updates, the user will naturally have a reactive application. What's more, the application will generally be responsive because these patterns naturally keep slow running queries and updates off the application main thread.

Room provides an excellent addition to the standard Android data storage ecosystem, not only dramatically reducing the need to write boilerplate data access code, but also providing a well-defined and excellently-written interface to run reactive queries for data. Of course, not all of your application needs to be reactive; once an object is delivered via a LiveData object, it's just an object and can be used as an in-memory snapshot or even edited if it's mutable.

When using Room, it's important...

lock icon The rest of the chapter is locked
You have been reading a chapter from
Hands-On Android UI Development
Published in: Nov 2017 Publisher: Packt ISBN-13: 9781788475051
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime}