Data Storage in Android Apps
Data Storage in Android Apps
27-Oct-24 By Mistre E. 1
Chapter Four
Storing and Retrieving Data
2
Working with a Content Provider
In Android, Content Providers are a very important component that
serves the purpose of a relational database to store the data of
applications.
The role of the content provider in the android system is like a
central repository in which data of the applications are stored, and it
facilitates other applications to securely access and modifies that
data based on the user requirements.
Android system allows the content provider to store the application
data in several ways.
Users can manage to store the application data like images, audio,
videos, and personal contact information by storing them in SQLite
Database, in files, or even on a network.
In order to share the data, content providers have certain permissions
that are used to grant or restrict the rights to other applications to
interfere with the data.
3
Cont’d
The content provider is free to store the data in whatever back-end
representation it chooses, be it the file system, the SQLite service,
or some application-specific representation (including those
implemented via remote web services).
4
Content URI
Content URI (Uniform Resource Identifier): is the key concept of
Content providers. To access the data from a content provider, URI is
used as a query string.
Structure of a Content
URI: content://authority/optionalPath/optionalID
content:// – Mandatory part of the URI as it represents that the
given URI is a Content URI.
authority – Signifies the name of the content provider like contacts,
browser, etc. This part must be unique for every content provider.
optionalPath – Specifies the type of data provided by the content
provider. It is essential as this part helps content providers to support
different types of data that are not related to each other like audio and
video files.
optionalID – It is a numeric value that is used when there is a need
to access a particular record.
5
Operations in Content Provider
6
Cont’d
Working of the Content Provider UI components of android
applications like Activity and Fragments use an
object CursorLoader to send query requests to ContentResolver.
The ContentResolver object sends requests (like create, read, update,
and delete) to the ContentProvider as a client.
After receiving a request, Content Provider process it and returns the
desired result.
7
Store and retrieving data in Android
Android provides several options for you to save persistent
application data.
Android provides a way for you to expose even your private data to
other applications with a content provider.
8
Cont’d
The solution you choose depends on your specific needs, such as
whether the data should be private to your application or accessible
to other applications (and the user) and how much space your data
requires.
Internal Storage,
External Storage,
Network Connection.
9
Cont’d
Using Shared Preferences: Store private primitive data in key-value
pairs.
The Shared Preferences class provides a general framework that
allows you to save and retrieve persistent key-value pairs of primitive
data types. You can use Shared Preferences to save any primitive
data: booleans, floats, ints, longs, and strings. This data will persist
across user sessions (even if your application is killed).
User Preferences
Shared preferences are not strictly for saving “user preferences,” such
as what ringtone a user has chosen.
If you’re interested in creating user preferences for your application,
see Preference Activity, which provides an Activity framework for
you to create user preferences, which will be automatically persisted
(using shared preferences).
10
Cont’d
To get a Shared Preferences object for your application, use one of
two methods:
GetSharedPreferences() : use this if you need multiple preferences
files identified by name, which you specify with the first parameter.
GetPreferences() : use this if you need only one preferences file
for your Activity. Because this will be the only preferences file for
your Activity, you don’t supply a name.
To write values:
Call edit()to get a [Link].
Add values with methods such as putBoolean() and putString().
Commit the new values with commit()
To read values:
Use SharedPreferencesmethods such as getBoolean()
and getString().
11
Cont’d
Here is an example that saves a preference for silent keypress mode in a calculator:
public class Calc extends Activity {
public static final String PREFS_NAME = "MyPrefsFile";
@Override
protected void onCreate(Bundle state){
[Link](state);
// Restore preferences
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = [Link]("silentMode", false);
setSilent(silent);
}
@Override
protected void onStop(){
[Link]();
// We need an Editor object to make preference changes.
// All objects are from [Link]
SharedPreferences settings = getSharedPreferences(PREFS_NAME,0);
[Link] editor = [Link]();
[Link]("silentMode", mSilentMode);
// Commit the edits!
[Link]();
}
}
12
Cont’d
Using the Internal Storage: Store private data on the device memory.
You can save files directly on the device’s internal storage. By
default, files saved to the internal storage are private to your
application and other applications cannot access them (nor can the
user).
When the user uninstalls your application, these files are removed.
To create and write a private file to the internal storage:
Call openFileOutput()with the name of the file and the operating
mode. This returns a FileOutputStream.
Write to the file with write().
Close the stream with close().
13
Cont’d
For example:
String FILENAME = "hello_file";
String string = "hello world!";
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
[Link]([Link]());
[Link]();
MODE_PRIVATE will create the file (or replace a file of the same
name) and make it private to your application. Other modes available
are: MODE_APPEND, MODE_WORLD_READABLE,
and MODE_WORLD_WRITEABLE.
To read a file from internal storage:
Call openFileInput()and pass it the name of the file to read. This
returns a FileInputStream.
Read bytes from the file with read().
Then close the stream with close().. 14
Cont’d
Saving cache files
If you’d like to cache some data, rather than store it persistently,
you should use getCacheDir()to open a File that represents the
internal directory where your application should save temporary
cache files.
When the device is low on internal storage space, Android may
delete these cache files to recover space. However, you should not
rely on the system to clean up these files for you.
You should always maintain the cache files yourself and stay within
a reasonable limit of space consumed, such as 1MB. When the user
uninstalls your application, these files are removed.
15
Cont’d
Other useful methods
getFilesDir()
Gets the absolute path to the file system directory where your internal
files are saved.
getDir()
Creates (or opens an existing) directory within your internal storage
space.
deleteFile()
Deletes a file saved on the internal storage.
fileList()
Returns an array of files currently saved by your application.
16
Cont’d
Using the External Storage: store public data on shared external storage.
Every Android-compatible device supports a shared “external storage”
that you can use to save files. This can be a removable storage media
(such as an SD card) or an internal (non-removable) storage.
Files saved to the external storage are world-readable and can be
modified by the user when they enable USB mass storage to transfer
files on a computer.
Caution: External files can disappear if the user mounts the external
storage on a computer or removes the media, and there’s no security
enforced upon files you save to the external storage. All applications can
read and write files placed on the external storage and the user can
remove them.
Checking media availability
Before you do any work with the external storage, you should always
call getExternalStorageState() to check whether the media is
available. 17
Cont’d
The media might be mounted to a computer, missing, read-only, or in some other
state. For example, here’s how you can check the availability:
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = [Link]();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
mExternalStorageAvailable = mExternalStorageWriteable = true;
}
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// We can only read the media
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
// Something else is wrong. It may be one of many other states, but all we need
// to know is we can neither read nor write
mExternalStorageAvailable = mExternalStorageWriteable = false;
} 18
Cont’d
Accessing files on external storage
If you’re using API Level 8 or greater, use getExternalFilesDir() to
open a File that represents the external storage directory where you
should save your files.
This method takes a type parameter that specifies the type of
subdirectory you want, such as DIRECTORY_MUSIC
and DIRECTORY_RINGTONES (pass null to receive the root of
your application’s file directory).
By specifying the type of directory, you ensure that the Android’s
media scanner will properly categorize your files in the system (for
example, ringtones are identified as ringtones and not music).
If the user uninstalls your application, this directory and all its
contents will be deleted.
19
Cont’d
If you’re using API Level 7 or lower,
use getExternalStorageDirectory(), to open a File representing the
root of the external storage. You should then write your data in the
following directory:
/Android/data/<package_name>/files/ The <package_name>is
your Java-style package name, such as
“[Link]“.
Hiding your files from the Media Scanner
Include an empty file named .nomediain your external files
directory (note the dot prefix in the filename).
This will prevent Android’s media scanner from reading your media
files and including them in apps like Gallery or Music.
20
Cont’d
Saving files that should be shared
If you want to save files that are not specific to your application and
that should not be deleted when your application is uninstalled,
save them to one of the public directories on the external storage.
These directories lay at the root of the external storage, such as
Music/, Pictures/, Ringtones/, and others.
In API Level 8 or greater,
use getExternalStoragePublicDirectory(),passing it the type of
public directory you want, such
as DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTOR
Y_RING ONES, or others. This method will create the appropriate
directory if necessary.
If you’re using API Level 7 or lower,
use getExternalStorageDirectory() to open a Filethat represents
the root of the external storage, then save your shared files in one of
the following directories:
21
Cont’d
Music/ – Media scanner classifies all media found here as user music.
23
Cont’d
Using Databases: store structured data in a private database.
25
Cont’d
To write to and read from the database,
call getWritableDatabase()and getReadableDatabase(), respectively.
These both return a SQLiteDatabaseobject that represents the database
and provides methods for SQLite operations.
Database debugging
26
Android Storing and Retrieving Data
Data has always been the most important part of any mobile
application.
Developers need to store substantial amounts of data in an
organized fashion in order for their apps to be truly valuable to their
users.
Android supports data storage in a local database, and the operating
system provides a good infrastructure for storing and retrieving
data. In most cases, the most simple and straightforward way to
acquire and preserve user data is via SQLite databases.
SQLite
SQLite is a relational database technology that’s used most often
when the developer requires an embedded database in a small
system. SQLite is included with the Android system and can be
easily used in your Android app.
27
Cont’d
Creating a Database in Android
In order to write data to a database, we need to create our database
first.
For managing all the operations related to the database, a helper class
has been given and is called SQLiteOpenHelper. It automatically
manages the creation and update of the database.
The SQLiteOpenHelper constructor accepts four arguments, which are:
Context – This is the context that will be used to create the database.
(Here you can pass the Activity object.)
Name – The name of the new database file.
Factory – A cursor factory (you can usually pass this as null)
Version – The version of the database. This number is used to
identify if there is an upgrade or downgrade of the database.
28
Cont’d
Below, we ’ve created a class (MyDatabaseHelper) that is going to derive from
SQLiteOpenHelper:
public class MyDatabaseHelper extends SQLiteOpenHelper{
private static final String DATABASE_NAME=”MyFriendsDatabase”;
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase database) {
[Link](“CREATE TABLE friends (_id INTEGER PRIMARY KEY
AUTOINCREMENT, name TEXT, phonenumber INTEGER);”);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
[Link](“DROP TABLE IF EXISTS friends”);
onCreate(db);
}
}
29
Cont’d
In the constructor above, we pass the name of the database that we
want to create called as “MyFriendsDatabase.” We also override the
following methods:
onCreate: This method is called when we create the database. It is
passed the SQLiteDatabase reference, which we can use to perform
various operations on the database.
In this method, we use the function execSQL to execute an SQL
query to create a table called “friends,” which has three columns.
The first column, (_id) is required to generate a unique id for each
column. The second and third columns (name and phone number)
are the data fields that we actually want to store.
onUpgrade: This method is called whenever the database is upgraded.
In this method, SQLiteDatabase and the oldVersion number and
newVersion number are passed.
In this function, we simply drop the “friends” table if it exists and
create a new one. 30
Cont’d
Adding Values within the Database
Once the database is created, we are going to use the insert function
on the SQLiteDatabase class.
The insert function takes three arguments: the name of the table in
which to insert values, the name of one of the column of the table,
and a reference to a ContentValues
In class MyDatabaseHelper below, we will write a function to insert
values into the database.
public void addFriend(String name,int phonenumber)
{
ContentValues values=new ContentValues(2);
[Link](“name”, name);
[Link](“phonenumber”, phonenumber);
getWritableDatabase().insert(“friends”, “name”, values);
}
31
Cont’d
In this function, we take the input arguments as the name and the
phonenumber. Then, we create a new object of ContentValues, we
put the values for name and phonenumber within that new object.
Once we have done that, we get the SQLiteDatabase reference for
writing using the function getWritableDatabase, which is a member
of SQLiteOpenHelper. Once we have the reference of the
SQLiteDatabase, we call the insert function, which takes the
arguments as the table name, one of the columns of the table, and
the ContentValues. This will enter a new row in your friends
database table.
If you want to use MyDatabaseHelper to create a database and add
some data values, the code would be as follows:
public void onCreate(Bundle savedInstanceState) {
[Link](savedInstanceState);
setContentView([Link]);
databaseHelper = new MyDatabaseHelper(this);
[Link](“Abbas”, 987);
[Link](“John”, 9877);
[Link](“Michael”, 8334);
} 32
Cont’d
Once we have added the data into the database, we will now see
how the data can be retrieved. To retrieve the data, there are two
possible methods:
Runing a raw SQL query
We can directly run an SQL query like SELECT to retrieve the
records from the database.
To run a raw SQL query, you have the function rawQuery, which
takes the SQL statement as a string as its first parameter and the
selection arguments as its second parameter. So, if we have to write
a function in MyDatabaseHelper to retrieve all records from table
friends, it would be as follows:
public Cursor getFriends()
{ Cursor cursor = getReadableDatabase().rawQuery(“select * from friends”, null);
return cursor;
}
33
Cont’d
To Run Queries on Database
We can also run queries on the database using the function query on
the SQLiteDatabase.
The query function lets you query on one table and also specify
some selection and ordering criteria.
The query function takes several arguments: the name of the table,
the name of the columns of the table to retrieve, the selection
criteria, the arguments for selection criteria, the group by clause, the
having clause, the order by clause, and the limit.
If we have to write the same function above to retrieve all friends
using query, it would be as follows:
public Cursor getFriends()
{
Cursor cursor = getReadableDatabase().query(“friends”,
new String[] { “_id”, “name”, “phonenumber”}, null, null, null, null, null);
return cursor;
}
34
Cont’d
The Database Cursor
The result of a query is returned in form of a Cursor object, which
basically helps by caching the result of the query in an efficient way
and providing functions to access the data.
If we want to fetch the data of all friends from the Cursor returned
by the getFriends function, we would write the following code:
36
Cont’d
37
Cont’d
Using a Network Connection: store data on the web with your own
network server
You can use the network (when it’s available) to store and retrieve
data on your own web-based services.
There are various providers of cloud storage(Google Drive gives
15GB of free storage).
To do network operations, use classes in the following packages:
[Link].*
[Link].*
38
Synchronization and Replication of Mobile Data
Data synchronization is a method of establishing consistency among
data from a data source to the target data storage and vice versa.
In data synchronization, we have to keep multiple copies of a dataset
in coherence with one another to maintain the data integrity.
Local synchronization involves devices and computers that are next
to each other, while remote synchronization takes place over a
mobile network.
Data must always be consistent throughout the data record. If data is
modified in any way, changes must upgrade through every system in
real-time to avoid mistakes, prevent privacy breaches, and ensure that
the most up-to-date data is the only information available.
Data synchronization ensures that all records are consistent, all the
time.
39
Cont’d
Data synchronization is important and required in mobile
computing because it checks the differences between two data
containers or data sources and data receivers to restrict the
unnecessary transfer of data that already resides in both data
sources.
The data synchronization process typically updates both data
sources by transferring only additions, changes, and deletions.
The reasons why data synchronization is required in Mobile
computing are:
Data synchronization is required between the mobile devices and
their service provider.
It is also required between the device and personal area computer
and nearby wireless access points (in Wi-Fi connection) and other
nearby devices.
It is used to establish consistency among data from a data source to
the target data storage and vice versa.
40
Cont’d
Few types of data synchronization methods:
File Synchronization: Faster and more error-proof than a manual
copy technique, this method is most used for home backups, external
hard drives, or updating portable data via flash drive. File
synchronization ensures that two or more locations share the same
data, occurs automatically, and prevents duplication of identical files.
Version Control: This technique aims to provide synchronizing
solutions for files that can be altered by more than one user at the
same time.
Distributed File Systems: When multiple file versions must be
synced at the same time on different devices, those devices must
always be connected for the distributed file system to work.
Mirror Computing: Mirror computing is used to provide different
sources with an exact copy of a data set. Especially useful for backup,
mirror computing provides an exact copy to just one other location
source to target.
41
42