Chapter 17. Data Persistence and Sharing
In this chapter, we will look at a couple of different ways to save data to an Android device's permanent storage. Also, for the first time, we will add a second Activity
instance to our app. It often makes sense when implementing a separate "screen", such as a "Settings" screen, in our app to do so in a new Activity
instance. We could go to the trouble of hiding the original UI and then showing the new UI in the same Activity
, as we did in Chapter 4, Getting Started with Layouts and Material Design, but this would quickly lead to confusing and error-prone code. So, we will see how to add another Activity
instance and navigate the user between them.
In this chapter, we will do the following:
Learn about the Android Intent
class to switch Activity
instances and pass data between them
Create a very simple settings screen in a new Activity
instance
Persist the settings screen data using the SharedPreferences
class
Learn about JavaScript Object Notation (JSON...
The Intent
class is appropriately named. It is a class that demonstrates the intent of an Activity
instance from our app. It makes intent clear and it also facilitates it.
All our apps so far have had just one Activity
instance but many Android apps comprise more than one.
In perhaps its most common use, an Intent
object allows us to switch between Activity
instances. But, of course, Activity
instances are made from classes. So, what happens to the data when we switch between these classes? The Intent
class handles this problem for us as well by allowing us to pass data between them.
Intent
classes aren't just about wiring up the Activities of our app. They also make it possible to interact with other apps, too. For example, we could provide a link in our app for the user to send an email, make a phone call, interact with social media, or open a web page in a browser, and have the email, dialer, web browser, or relevant social media app do all the work.
There aren't...
Adding a settings page to Note to self
Now we are armed with all this knowledge about the Android Intent
class, we can add another screen (Activity
) to our Note to self app: a "Settings" screen.
We will first create a new Activity
instance for our new screen and see what effect that has on the AndroidManifest.xml
file. We will then create a very simple layout for our settings screen and add the Kotlin code to switch from MainActivity
to the new one. We will, however, defer wiring up our settings screen layout with Kotlin until we have learned how to save the users preferred settings to disk. We will do this later on in this chapter and then come back to the settings screen to make its data persist.
First, let's code that new Activity
class. We will call it SettingsActivity
.
Creating the SettingsActivity
SettingsActivity will be a screen where the user can turn on or off the decorative divider between each note in the RecyclerView
widget. This will not be a very comprehensive settings screen...
Persisting data with SharedPreferences
In Android, there are a few ways to make data persist. By persist, I mean that if the user quits the app, then when they come back to it their data will still be available. Which technique is the correct one to use is dependent upon the app and the type of data.
In this book, we will look at three ways to make data persist. For saving our user's settings, we only need a simple method. After all, we just need to know whether they want the decorative divider between each of the notes in the RecyclerView
widget.
Let's look at how we can make our apps save and reload variables to the internal storage of the device. We need to use the SharedPreferences
class. SharedPreferences
is a class that provides access to data that can be accessed and edited by all the classes of an app. Let's look at how we can use it:
Reloading data with SharedPreferences
Let's see how we can reload our data the next time the app is run. This code will reload the three values that the previous code saved. We could even declare our variables and initialize them with the stored values:
In the previous code, we load the data from disk using the function appropriate for the data type and the same label we used to save the data in the first place. What is less clear is the second argument to each of the function calls.
The getString
, getInt
, and getBoolean
functions require a default value as the second argument. If there is no data stored with that label, it will then return the default value.
We could then check for these default values in our code and go about trying to obtain the required values or handling an error. For example, see the following code:
Making the Note to self settings persist
We have already learned how to save data to the device's memory. As we implement saving the user's settings, we will, again, see how we handle the Switch
widget input and where exactly the code we have just seen will go to make our app work the way we want it to.
Coding the SettingsActivity class
Most of the action will take place in the SettingsActivity.kt
file. So, click on the appropriate tab and we will add the code a bit at a time.
First, we want a property to represent the user's option on the settings screen – whether they want decorative dividers or not.
Add the following to SettingsActivity
:
Now, in onCreate
, add the highlighted code to initialize prefs
, which is inferred to be a SharedPreferences
instance:
Note
Import the SharedPreferences
class:
Next, still in onCreate...
More advanced persistence
Let's think about what we need to do. We want to save a bunch of notes to the internal storage. Being more specific, we want to store a selection of Strings and related Boolean values. These Strings and Boolean values represent the user's note title, the text, and whether it is a to-do, important, or an idea.
Given what we already know about the SharedPreferences
class, at first glance, this might not seem especially challenging – until we dig a little deeper into our requirements. What if the user loves our app and ends up with 100 notes? We would need 100 identifiers for key-value pairs. Not impossible, but starting to get awkward.
Now, imagine that we wanted to enhance the app and give the user the ability to add dates to them. Android has a Date
class that is perfect for this. It would be reasonably straightforward to then add neat features, such as reminders, to our app. But when it comes to saving data, things suddenly start to get complicated.
How would we...
Backing up user data in Note to self
So, with our new-found insight into exceptions, let's modify our Note to self code, and then we can be introduced to JSONObject
and JSONException
.
First, let's make some minor modifications to our Note
class.
Add some more properties that will act as the key in a key-value pair for each aspect of our Note
class:
Now, add a constructor and an empty default constructor that receives a JSONObject
reference and throws a JSONException
error. The body of the first constructor initializes each of the members that define the properties of a single Note
object by calling the getString
or getBoolean
function of the JSONObject
class, passing in the key as an argument. We also provide an empty constructor, which is required so that we can also create a Note
object with uninitialized properties...
Frequently asked questions
Q.1) I didn't understand everything in this chapter, so am I cut out to be a programmer?
A) This chapter introduced many new classes, concepts, and functions. If your head is aching a little, that is to be expected. If some of the detail is unclear, don't let it hold you back. Proceed with the next couple of chapters (they are much more straightforward), then revisit this one, and especially examine the completed code files.
Q.2) So, how does serialization work in detail?
A) Serialization really is a vast topic. It is possible to write apps your whole life and never really need to understand it. It is the type of topic that would be the subject of a computer science degree. If you are curious to know more, have a look at this article: https://en.wikipedia.org/wiki/Serialization.
At this point in our journey through the Android API, it is worth taking stock of what we know. We can lay out our own UI designs, and can choose from a wide and diverse range of widgets to allow the user to interact. We can create multiple screens, as well as pop-up dialogs, and we can capture comprehensive user data. Furthermore, we can now make this data persist.
Certainly, there is a lot more to the Android API still to learn, even beyond what this book will teach you, but the point is that we know enough now to plan and implement a working app. You could get started on your own app right now.
If you have the urge to start your own project right away, then my advice is to go ahead and do it. Don't wait until you consider yourself "expert" or more ready. Reading this book and, more importantly, implementing the apps will make you a better Android programmer, but nothing will teach you faster than designing and implementing your own app! It is perfectly possible to read this book...