You are on page 1of 53

Chapter Three

SQLITE DATABASES
3. SQLITE Databases
Topics Covered
 Overview of Storage in Android
 Why sqlite
 Sqlite classes
 Storage class and data types
 Database
• Create database
• Insert data into database
• Update and Delete data
 Retrieve information
 Get reference to database
 Get data from the database(cursor)
 Return records
Storage in Android
 There are different ways to store data in android.
 App-specific storage
 Shared storage
 Preferences

 Databases

 App specific storage: Store files that are meant for your app's use only,
either in dedicated directories within an internal storage volume or
different dedicated directories within external storage.
 Use the directories within internal storage to save sensitive information
that other apps shouldn't access.
 The directories include both a dedicated location for storing persisting files
and another location for storing cache data.
 N.B you shouldn't use this storage to save anything that the user expects
to persist independently of your app
Cont’d
 Shared storage: Store files that the app intends to share with other apps, including
media, documents, and other files.
 The data can be accessible and saved even if the user uninstalls the app.
 Android provides APIs for storing and accessing the following types of shareable
data:
 Media Content: The system provides standard public directories for these kinds of
files, so the user has a common location for all their photos, another common
location for all their music and audio files. Our App can access this content using
MediaStore API.
 Document and other files: The system has a special directory for containing other file
types, such as PDF documents and books that use the EPUB format. Your app can
access these files using the platform's Storage Access Framework.
 Datasets: On Android 11 (API level 30) and higher, the system caches large datasets
that multiple apps might use. These datasets can support use cases like machine
learning and media playback.
Cont’d
 Preferences: Store private, primitive data in key-value pairs. As the name
suggests, the primary purpose is to store user-specified configuration
details, such as user specific settings, keeping the user logged into the
application.

 You build a settings screen for your app using the Preferences API. This
allows you to add individual preferences, and record a value for each
preference. These values are recorded in a shared preferences file for your
app. Data is lost
• on uninstalling the application
• on clearing the application data (through Settings)
 Databases: we can Store structured data in a private database.
Overview (Sqlite)
 Android uses SQLite databases to persist data.

 SQLite is an open-source relational database i.e. used to perform


database operations on android devices such as storing,
manipulating or retrieving persistent data from the database.

 Whenever an application needs to store large amount of data then


using sqlite is more preferable than other repository system
like Shared Preferences or saving data in files.

 It is available locally over the device(mobile & tablet) and contain


data in text format.
Why SQLite
 It’s lightweight
 Most database systems need a special database server process in
order to work. a SQLite database is just a file. When you’re not using
the database, it doesn’t use up any processor time
 It’s optimized for a single user
 Our app is the only thing that will talk to the database, so we
shouldn’t have to identify ourselves with a username and password.
 It’s stable and fast
 SQLite databases are amazingly stable. They can handle database
transactions, which means if you’re updating several pieces of data
and mess up, SQLite can roll the data back.
SQLite classes
 Android uses a set of classes that allows you to manage a SQLite
database
 We will use Three important types of object
 The SQLite Helper:
 A SQLite helper enables you to create and manage databases. You
create one by extending the SQLiteOpenHelper class.
 The SQLite Database:
 The SQLiteDatabase class gives you access to the database. It’s like
SQLConnection in JDBC.
Cont’d

 Cursors
 are what contain the result set of a query made against a database
in Android. It’s like a ResultSet in JDBC.
We’re going to use these objects to create SQLite database your app
can use to persist data
SQLite Helper

 The SQLite helper manages your database


 help you to create and maintain your SQLite databases. Think of it
as a personal assistant who takes care of the general database
housekeeping
 Creating the database:
 When you first install an app, the database file won’t exist. The
SQLite helper will make sure the database file is created with the
correct name and with the correct table structures installed.
Cont’d

 Getting access to the database:


Our app shouldn’t need to know all of the details about where the
database file is, so the SQLite helper can serve us with an easy-to-use
database object whenever we need it.
 Keeping the database shipshape:
The structure of the database will probably change over time, and the
SQLite helper can be relied upon to convert an old version of a
database into a new version, with all the latest database structures it
needs.
Create the SQLite Helper

 The sqlite helper class extends the SQLiteOpenHelper class


 The class must override onCreate() and onUpgrade() methods.
These methods are mandatory.
 The onCreate() method gets called when the database first gets
created on the device. The method should include all the code
needed to create the tables you need for your app.
 The onUpgrade() method gets called when the database needs to
be upgraded. As an example, if you need to modify the structure of
the database after it’s been released, this is the method to do it in.
class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
}
}
Specify the database name &
version
class DatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = “Caffe"; // the name of our
database
private static final int DB_VERSION = 1; // the version of the
database
DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
...
}
N.B The constructor specifies details of the database, but the
database doesn’t get created at that point. The SQLite helper
waits until the app needs to access the database, and then
Storage class and data types
 The data inside a SQLite database is stored in tables. A table contains
several rows, and each row is split into columns. A column contains a single
piece of data, like a number or a piece of text.
 Each column in a table is designed to store a particular type of data. For
example, in our DRINK table, the DESCRIPTION column
will only ever store text data.

Data Type Description


INTEGER Any integer type
TEXT Any character type
REAL Any floating-point number
NUMERIC Booleans, dates, and date-
times
BLOB Binary Large Object
Create Table using SQL

 Every application that talks to SQLite needs to use a standard database


language called Structured Query Language (SQL).
 We will create Drink table in the previous slide using the following syntax

CREATE TABLE DRINK (_id INTEGER PRIMARY KEY AUTOINCREMENT,


NAME TEXT,
DESCRIPTION TEXT,
IMAGE_RESOURCE_ID INTEGER)

 It’s an Android convention to call your primary key columns _id. Android
code expects there to be an _id column on your data. Ignoring this
convention will make it harder to get the data out of your database and
into your user interface.
The onCreate()method

 Called when the database is created


 The onCreate() method has one parameter, a SQLiteDatabase
object that represents the database that’s been created.
 SQLiteDatabase execSQL() method to execute SQL on the
database.
execSQL(String sql);

public void onCreate(SQLiteDatabase db){


db.execSQL("CREATE TABLE DRINK ("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "DESCRIPTION TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER);");
}
Insert() method
 To insert data into a table in a SQLite database, you start by
specifying what values you want to insert into the table
 ContentValues object is used for this purpose You add data to the
ContentValues object using its put() method. This method adds
name/value pairs of data:

ContentValues drinkValues = new ContentValues();


drinkValues.put("NAME", "Latte");
drinkValues.put("DESCRIPTION", "Espresso and steamed milk");
drinkValues.put("IMAGE_RESOURCE_ID", R.drawable.latte);
db.insert("DRINK", null, drinkValues);
Cont’d private static void insertDrink(SQLiteDatabase db,String name,String
description,
int resourceId) {
ContentValues drinkValues = new ContentValues();
drinkValues.put("NAME", name);
drinkValues.put("DESCRIPTION", description);
drinkValues.put("IMAGE_RESOURCE_ID", resourceId);
db.insert("DRINK", null, drinkValues);
}
insertDrink(db, "Latte", "Espresso and steamed milk", R.drawable.latte);
insertDrink(db, "Cappuccino", "Espresso, hot milk and steamed-milk
foam",
R.drawable.cappuccino);
insertDrink(db, "Filter", "Our best drip coffee", R.drawable.filter);
Update() method
 The update() method lets you update records in the database, and
returns the number of records it’s updated
 To use the update() method, you specify the table you want to
update records in, the ContentValues object that contains the
values you want to update, and the conditions for updating them.
 This code will change the value of the DESCRIPTION column to
“Tasty” where the name of the drink is “Latte”:

ContentValues drinkValues = new ContentValues();


drinkValues.put("DESCRIPTION", "Tasty");
db.update("DRINK",
drinkValues,
"NAME = ?",
new String[] {"Latte"});
Apply condition to Multiple column
db.update("DRINK",
drinkValues,
"NAME = ? OR DESCRIPTION = ?",
new String[] {"Latte", "Our best drip coffee"});
N.B The condition values must be Strings, even if the column you’re
applying the condition to contains some other type of data. As an
example, here’s how you’d update DRINK records where the _id
(numeric) is 1:
db.update("DRINK",
drinkValues,
"_id = ?",
new String[] {Integer.toString(1)});
Delete() method

 You delete records using the SQLiteDatabase delete() method


 This code will delete all records from the DRINK table where the
name of the drink is “Latte”:

db.delete("DRINK",
"NAME = ?",
new String[] {"Latte"});
Version control
 The onCreate() method will make sure that all new users get the new
column.
 The onUpgrade() method will make sure that all existing users get it too.
upgrade on the database can be taken due to
 Change the database records. We may want to add more records
when you upgrade the database, or update or delete the records that
are already there.
 Change the database structure. We may also want to add columns to
existing tables, rename tables, or remove tables completely.
E.g [update the structure of DB]
 Class …. extends SQLiteOpenHelper{
private static final String DB_NAME = “Caffe"; // the name of our database
private static final int DB_VERSION = 2; // the version of the database
….(Context context){ ---------- Constructor
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db){
updateMyDatabase(db, 0, DB_VERSION);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
updateMyDatabase(db, oldVersion, newVersion);
}
Cont’d
 private void updateMyDatabase(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 1) {
db.execSQL("CREATE TABLE DRINK (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "DESCRIPTION TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER);");
insertDrink(db, "Latte", "Espresso and steamed milk", R.drawable.latte);
insertDrink(db, "Cappuccino", "Espresso, hot milk and steamed-milk foam", R.drawable.cappuccino);
insertDrink(db, "Filter", "Our best drip coffee", R.drawable.filter);
}
if (oldVersion < 2) {
db.execSQL("ALTER TABLE DRINK ADD COLUMN FAVORITE NUMERIC;");
}
}
Retrieve data
We will retrieve the information in the database by following these
procedures:
 Get a reference to the database.
 Create a cursor to read data from the database.
 Return all the records from a table
 Get a reference to the database
SQLiteOpenHelper databaseHelper = new DatabaseHelper(this);
 You then call SQLite helper’s getReadableDatabase() or
getWritableDatabase() to get a reference to the database.
 getReadableDatabase() is used if you need read-only access to the
database.
 getWritableDatabase() method is used if you need to perform any
updates
SQLiteOpenHelper Helper = new DatabaseHelper(this);
try {
SQLiteDatabase db = Helper.getReadableDatabase();
//Code to read data from the database
} catch(SQLiteException e) {
Toast toast = Toast.makeText(this,
"Database unavailable",
Toast.LENGTH_SHORT);
toast.show();
}
Cont’d
 Create a cursor to read data from the database
 A cursor lets you read from and write to the database. You specify what data
you want access to, and the cursor brings back the relevant records from the
database. You can then navigate through the records supplied by the
cursor.
 You create a cursor using the SQLiteDatabase query() method:
 Android uses the query() method to construct an SQL SELECT statement.

Cursor cursor = db.query(...);

 Return all the records from a table


Cursor cursor = db.query("DRINK",
new String[] {"_id","NAME", "DESCRIPTION"},
null, null, null, null, null);
 Return selected records: this cursor will return records from Drink
table where the drink id is 1

Cursor cursor = db.query ("DRINK",


new String[] {"NAME", "DESCRIPTION", "IMAGE_RESOURCE_ID"},
"_id = ?",
new String[] {Integer.toString(1)},
null, null, null);

 Return records in a particular order:

Cursor cursor = db.query("DRINK",


new String[] {"_id", "NAME", "FAVORITE"},
null, null, null, null,
"NAME ASC")
Navigate Cursors
 what data(record) the cursor to return is already fulfilled.
 once you have a cursor, you need to read values from it.
 Whenever you need to retrieve values from a particular record
in a cursor, you first need to navigate to that record.
 There are four main methods you use to navigate through the
records in a cursor:
moveToFirst(), moveToLast(), moveToPrevious(), and moveToNext().
 You retrieve values from a cursor’s current record using the cursor’s
get*() methods: getString(), getInt(), and so on. The exact method
you use depends on the type of value you want to retrieve. To get a
String value, for example, you’d use the getString() method, and to
get an int value you’d use getInt().
Finally, close the cursor and the
database
 Once you’ve finished retrieving values from the cursor, you need to close the
cursor and the database in order to release their resources. You do this by
calling the cursor and database close() methods:
 cursor.close(); Drink Detail Activity
 db.close(); SQLiteDatabase db =
DatabaseHelper.getReadableDatabase();
Cursor cursor = db.query ("DRINK",
new String[] {"NAME", "DESCRIPTION",
"IMAGE_RESOURCE_ID"},
"_id = ?",
new String[] {Integer.toString(drinkId)},
null, null, null);
if (cursor.moveToFirst()) {
//Get the drink details from the cursor
String nameText = cursor.getString(0);
String descriptionText = cursor.getString(1);
List View to display data
 ListViews and Spinners can use any subclass of the Adapter class for
their data.
This includes ArrayAdapter, CursorAdapter, and SimpleCursorAdapter (a
subclass of CursorAdapter).
 A simple cursor adapter is a type of cursor adapter that can be used
in most cases where you need to display cursor data in a list view.
 A simple cursor adapter maps cursor data to views.
How the mapping works?
Simple Cursor Adapter
 Simple cursor adapter works in similar way with array adapter. We
initialize the adapter then we attach to the list view.
 The simple Cursor Adapter Constructor looks like:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(Context
context, Current activity
int layout, How to display the data
Cursor cursor, The cursor you create
String[] fromColumns,
Which column in the cursor t which
int[] toViews, views
int flags)
Determine the cursor behavior
Close the cursor and database

 When we use a cursor adapter in order to show a list of database


records; the cursor adapter needs the cursor to stay open in case it
needs to retrieve more data from it.
 We can’t close the cursor and database once you’ve used the
setAdapter() method.
 The cursor and database will be closed in the activity’s onDestroy()
method.
Exercise // Drink Category Activity
private SQLiteDatabase db;
 private Cursor cursor;
onCreate(){
SQLiteOpenHelper DatabaseHelper = new DatabaseHelper(this);
try {
db = DatabaseHelper.getReadableDatabase();
cursor = db.query("DRINK",
new String[]{"_id", "NAME"},
null, null, null, null, null);
SimpleCursorAdapter listAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
cursor,
new String[]{"NAME"},
new int[]{android.R.id.text1},
0);
listDrinks.setAdapter(listAdapter);
}
catch(SQLiteException e) {
Toast toast = Toast.makeText(this, "Database unavailable", Toast.LENGTH_SHORT);
toast.show();
Update Records

 Add favorite check box in detail drink activity layout


 Automatically check/uncheck the box by checking the
value from the database
 If the checkbox was checked by the user, the drink
favorite column will be updated and displayed in the
main activity layout
Cont’d [Update Records]
 Check the status of Favorite column

boolean isFavorite = (cursor.getInt(3) == 1);


CheckBox favorite =
(CheckBox)findViewById(R.id.favorite);
favorite.setChecked(isFavorite);

 Next we see how to Update the column when check box is selected
ContentValues drinkValues = new ContentValues();
 drinkValues.put("FAVORITE", favorite.isChecked());
//Get a reference to the database and update the FAVORITE column
SQLiteOpenHelper starbuzzDatabaseHelper = new
StarbuzzDatabaseHelper(this);
try {
SQLiteDatabase db = starbuzzDatabaseHelper.getWritableDatabase();
db.update("DRINK",
drinkValues,
"_id = ?",
new String[] {Integer.toString(drinkId)});
db.close();
} catch(SQLiteException e) {
Toast toast = Toast.makeText(this, "Database unavailable",
Toast.LENGTH_SHORT);
toast.show();
}
Exercise
 Display the list view in main activity as favorite Drinks
 When the item is clicked start detail Activity
 What you observe when you go back to the main activity after you
uncheck the drink value?
Change cursor()
 Cursors don’t automatically keep track of whether the underlying
data in the database has changed
 Cursors retrieve data when the cursor gets created. So, we create
the cursor on the oncreate() method when the user navigate to
another activity it is stopped so the oncreate() method will not
recreated.
 We have to change the cursor with changeCursor()
 Define the cursor
 Get reference to the cursor adapter: use getAdapter() method
 Change the cursor using changeCursor() method.

@Override
public void onRestart() {
super.onRestart();
Cursor newCursor = db.query("DRINK",
new String[] { "_id", "NAME"},
"FAVORITE = 1",
null, null, null, null);
ListView listFavorites = (ListView) findViewById(R.id.list_favorites);
CursorAdapter adapter = (CursorAdapter) listFavorites.getAdapter();
adapter.changeCursor(newCursor);
Youroldcursor = newCursor;
}
AsyncTask
 Database are very powerful, but they can be slow.
 The Database needs to go searching for the database file, if it is not
available it needs to create it.
 It needs to run all of the SQL commands {Creating tables, insert data
as well as retrieving data’s from db}
 As a database gets bigger and bigger, the time to perform the
database operations will also increase.
 We can increase our app responsiveness by using threads.
 Since Lollipop, there are three kinds of threads you need to think
about:
Cont’d
 The main event thread
 This is the real workhorse in Android. It listens for intents, it receives
touch messages from the screen, and it calls all of the methods
inside your activities.
 The render thread
 You don’t normally interact with this thread, but it reads a list of
requests for screen updates and then calls the device’s low-level
graphics hardware to repaint the screen and make your app look
pretty.
 Any other threads that you create
 In order to increase the performance, move your database code
off the main event thread and run it in a custom thread in the
background.
In the Drink Activity Code
 Choose the type of thread you think each should run on.
In the main thread or In the background thread
1) int drinkId = (Integer) 2)
getIntent().getExtras().get(EXTRA_DRINKID); SQLiteOpenHelper
CheckBox favorite = (CheckBox) starbuzzDatabaseHelper = new
findViewById(R.id.favorite); StarbuzzDatabaseHelper(this);
ContentValues drinkValues = new SQLiteDatabase db =
ContentValues(); starbuzzDatabaseHelper.getWriteableDat
drinkValues.put("FAVORITE", abase();
favorite.isChecked()); db.update("DRINK",...);

3)
Toast toast = Toast.makeText(...);
toast.show();
Async Task performs asynchronous
tasks
 AsyncTask lets you perform operations in the background

 After AsyncTask performs its task, then it allows you to update views
in the main event thread.

 You create an AsyncTask by extending the AsyncTask class, and


implementing its doInBackground() method.
You add your AsyncTask
AsyncTask class class as an inner class to the
activity that needs to use it.

private class MyAsyncTask extends AsyncTask<Params, Progress, Result>


protected void onPreExecute() {
//Code to run before executing the task
}
protected Result doInBackground(Params... params) {
//Code that you want to run in a background thread
}
protected void onProgressUpdate(Progress... values) {
//Code that you want to run to publish the progress of your task
}
protected void onPostExecute(Result result) {
//Code that you want to run when the task is complete
}
}
Async Task Parameters
 AsyncTask is defined by three generic parameters: Params,Progress,
and Results
 Params is the type of object used to pass any task parameters to the
doInBackground() method.
 Progress is type of object used to indicate task progress.
 Result is the type of the task result
 We will see how to use each methods in the context of Drink Activity
Class when Updating Favorite Drink.
The onPreExecute() Method
 This gets called before the background task begins, and it’s used to
set up the task. It’s called on the main event thread, so it has access
to views in the user interface.
 This method takes no parameters and has a void return type.

private class UpdateDrinkTask extends AsyncTask<Params, Progress,


Result> {
private ContentValues drinkValues;
protected void onPreExecute() {
CheckBox favorite = (CheckBox)findViewById(R.id.favorite); We are
drinkValues = new ContentValues(); accessing views
drinkValues.put("FAVORITE", favorite.isChecked());
}
...
}
The doInBackground() method
 This method runs in the background immediately after
onPreExecute().
 We define what type of parameters the task should receive, and
what the return type should be.
private class UpdateDrinkTask extends AsyncTask<Integer,
Boolean> {
private ContentValues drinkValues;
...
protected Boolean doInBackground(Integer... drinks
int drinkId = drinks[0];
SQLiteOpenHelper DatabaseHelper =
new DatabaseHelper(DrinkActivity.this);
try {
SQLiteDatabase db = DatabaseHelper.getWritableData
db.update("DRINK", drinkValues,
"_id = ?", new String[] {Integer.toString(drinkId)});
db.close();
return true;
} catch(SQLiteException e) {
return false;
The onProgressUpdate() method
 is called on the main event thread. so it has access to views in the
user interface.
 You can use this method to display progress to the user by updating
views on the screen.
 The onProgressUpdate() method runs if a call to publishProgress() is
made by the doInBackground() method like this:
protected Boolean doInBackground(Integer... count) {
for (int i = 0; i < count; i++) {
publishProgress(i);
}
}
protected void onProgressUpdate(Integer... progress) {
setProgress(progress[0]);
}

 We will not publish the progress of our task. So the AsyncTask class
will have the form <Integer, Void, Boolean>
The onPostExecute() method
 The onPostExecute() method is called after the background task has
finished.
 It is called in main event thread, so it has access to views in the user
interface.
 The result of the task can be presented in this method.
private class UpdateDrinkTask extends AsyncTask<Integer, Void,
Boolean> {
...
protected void onPostExecute(Boolean success) {
if (!success) {
Toast toast = Toast.makeText(DrinkActivity.this,
"Database unavailable", Toast.LENGTH_SHORT);
toast.show();
}
}
}
Execute the AsyncTask
 You run the AsyncTask by calling the AsyncTask execute() method
and passing it any parameters required by the doInBackground()
method.

int drinkId = (Integer) getIntent().getExtras().get(EXTRA_DRINKID);


new UpdateDrinkTask().execute(drinkId);

You might also like