Using SQLite in Android Development
Working with a subset of the MyRent app, we develop a module to persist data using SQLite, use the Android Debug Bridge (adb) commandline tool to view the database content and as an exercise replace the file system in MyRent with an SQLite implementation.
Baseline app
Create a baseline app named MyRentSQLite and complete the wizard screesn, following the steps shown in the following figures 1 to 4.
On completing the wizard, the app opens within Android Studio. This is shown in Figures 6 and 6.
Replace build.gradle (Module:app) with the following version to align with the Android configuration we have been using in this course:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "sqlite.myrentsqlite"
minSdkVersion 19
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
}
Build and install apk on a device or emulator to display the standard hello world screen as shown in Figure 6.
Project structure
To closely mimic the MyRent app structure, create three packages, activities, app and models as shown in the following pictures:
Move MyRent.java into the activities package. Unfortunately there is a bug in Android Studio 2.1.1 that cause the IDE to freeze if one attempts to drag and drop. This appears to have been resolved in version 2.1.3 but if not then simply copy and paste the file into activities and delete it from its original location.
We shall progressively implement the following features:
We begin with a restricted version of the Residence model class. It contains only 2 fields.
- Add a Residence object to the database.
- Delete a single Residence object from the database.
- Delete all Residence objects in the database.
- Obtain a list of all Residence objects in the database.
- Obtain a single nominated Residence object from the database.
- Add all remaining fields to the Residence model and test previously added features.
- Implement an update feature whereby an existing Residence object in the database may have some or all of its fields modified, excluding the primary key.
We will then have implemented Create, Read, Update and Delete (CRUD) capabilities.
Note: not all import statements are included in the code provided. Code completion hints are generally provided that simplifies this task.
Add Residence
We will build the app incrementally, beginning with the adding of a single Residence object to the database.
The refactoring comprises:
- Adding a button to the layout which when clicked causes a Residence object to be added to the database.
- Adding an event handler and other code to the activity MyRent to respond to a button click.
- Subclassing the Android Application class with a new class MyRentApp, located in the app package.
- Making changes to the AndroidManifest file to reflect the subclassing of the Application class.
- Subclassing the SQLiteOpenHelper class with a new class DbHelper, located in the app package.
- Adding a Residence model class that contains, for now, just two fields - the primary key and another.
The project structure, following refactoring, is depicted in Figure 1.
Manifest file
Here is the AndroidManifest.xml text. We have added the application name as an attribute (.app.MyRentApp
).
<?xml version="1.0" encoding="utf-8"?>
<manifest package="sqlite.myrentsqlite"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name=".app.MyRentApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".activities.MyRent">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Layout
The refactored layout file activity_myrent.xml
, both text and design views follow:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="sqlite.myrentsqlite.activities.MyRent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Residence"
android:id="@+id/addResidence"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
</RelativeLayout>
Model
package sqlite.myrentsqlite.models;
import java.util.UUID;
public class Residence
{
public UUID id;
public String geolocation;
public Residence()
{
id = UUID.randomUUID();
geolocation = "52.253456,-7.187162";
}
}
Application subclass
package sqlite.myrentsqlite.app;
import android.app.Application;
import android.util.Log;
public class MyRentApp extends Application
{
static final String TAG = "MyRentApp";
public DbHelper dbHelper = null;
private static MyRentApp app;
@Override
public void onCreate()
{
super.onCreate();
dbHelper = new DbHelper(getApplicationContext());
Log.d(TAG, "MyRent app launched");
app = this;
}
public static MyRentApp getApp(){
return app;
}
}
SQLiteOpenHelper subclass
package sqlite.myrentsqlite.app;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import sqlite.myrentsqlite.models.Residence;
public class DbHelper extends SQLiteOpenHelper
{
static final String TAG = "DbHelper";
static final String DATABASE_NAME = "residences.db";
static final int DATABASE_VERSION = 1;
static final String TABLE_RESIDENCES = "tableResidences";
static final String PRIMARY_KEY = "id";
static final String GEOLOCATION = "geolocation";
Context context;
public DbHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db)
{
String createTable =
"CREATE TABLE tableResidences " +
"(id text primary key, " +
"geolocation text)";
db.execSQL(createTable);
Log.d(TAG, "DbHelper.onCreated: " + createTable);
}
/**
* @param residence Reference to Residence object to be added to database
*/
public void addResidence(Residence residence)
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(PRIMARY_KEY, residence.id.toString());
values.put(GEOLOCATION, residence.geolocation);
// Insert record
db.insert(TABLE_RESIDENCES, null, values);
db.close();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("drop table if exists " + TABLE_RESIDENCES);
Log.d(TAG, "onUpdated");
onCreate(db);
}
}
Activity
package sqlite.myrentsqlite.activities;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import sqlite.myrentsqlite.R;
import sqlite.myrentsqlite.app.MyRentApp;
import sqlite.myrentsqlite.models.Residence;
public class MyRent extends AppCompatActivity implements View.OnClickListener
{
private Button addResidence;
MyRentApp app;
Residence residence;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_myrent);
app = MyRentApp.getApp();
addResidence = (Button) findViewById(R.id.addResidence);
addResidence.setOnClickListener(this);
}
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.addResidence:
addResidence();
break;
}
}
private void addResidence()
{
residence = new Residence();
app.dbHelper.addResidence(residence);
}
}
Test using adb
To check that the record is correctly inserted into the database we shall use the Android Debug Bridge (adb) commandline tool. You should refer to the Appendix for instructions in the configuration and use of adb.
Run MyRentSQLite app and add a residence by clicking on the Add Residence button.
Switch to a terminal and execute the command:
adb shell
The response should be:
root@generic_x86_64:/ #
Change directory as follows:
cd data/data
Check for the presence of our app:
ls -l
drwxr-x--x u0_a80 u0_a80 2016-07-15 10:57 sqlite.myrentsqlite
If, in Windows, you are unable to proceed further due to a permissions issue, then try the following as a solution:
- Open a windows command prompt as an administrator. You can do this by selecting the command prompt icon in the start menu and accessing the context menu.
- Then in the administrative command prompt run:
adb root
Change directory into sqlite.myrentsqlite.
cd sqlite.myrentsqlite
Check its contents:
ls -l
drwxrwx--x u0_a80 u0_a80 2016-07-15 10:57 cache
drwxrwx--x u0_a80 u0_a80 2016-07-15 10:57 code_cache
drwxrwx--x u0_a80 u0_a80 2016-07-15 10:57 databases
drwx------ u0_a80 u0_a80 2016-07-15 10:57 files
Change into databases folder and check the contents:
cd databases
ls -l
Here is typical output:
...
-rw-rw---- u0_a80 u0_a80 20480 2016-07-15 10:58 residences.db
-rw------- u0_a80 u0_a80 12824 2016-07-15 10:58 residences.db-journal
The database file residences.db is present. This name was assigned in the DbHelper class. We shall now inspect its contents. Run the following commands:
sqlite3 residences.db
The response should be something like the following:
SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
sqlite>
Check what tables are present in the database:
.tables
In our case the response should be as follows:
android_metadata tableResidences
sqlite>
We have added one Residence object record to the database. This can now be verified:
sqlite> select * from tableResidences;
efb14e04-0820-4cfc-9520-1f4c391d0974|52.253456,-7.187162
To exit sqlite run this command:
.exit
To exit adb run a similar command but without the period:
exit
Use the above technique to regularly check the database table(s) as you progressively develop the app.
Running .exit and exit in succession will return you to the terminal command prompt.
Official documentation:
Select a Residence
In this step, we provide the additional code to select a single residence from the database.
Layout (xml)
Add a Delete Residence button to the layout:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Select Residence"
android:id="@+id/selectResidence"
android:layout_alignBottom="@+id/addResidence"
android:layout_alignParentEnd="true"
android:layout_marginEnd="27dp"/>
DbHelper
Add this method to DbHelper.java:
public Residence selectResidence(UUID resId) {
Residence residence;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = null;
try {
residence = new Residence();
cursor = db.rawQuery("SELECT * FROM tableResidences WHERE id = ?", new String[]{resId.toString() + ""});
if (cursor.getCount() > 0) {
int columnIndex = 0;
cursor.moveToFirst();
residence.id = UUID.fromString(cursor.getString(columnIndex++));
residence.geolocation = cursor.getString(columnIndex++);
}
} finally {
cursor.close();
}
return residence;
}
These import statements are required:
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
MyRent (activity)
The following additional code snippets are required:
- A Button field.
- Binding of the button resource in the R file to the new button field.
- Setting a listener on the button.
- Intercepting a button click.
- Implementing a method selectResidence that in turn invokes DbHelper.deleteResidence.
Here are the code snippets:
private Button selectResidence;
selectResidence = (Button) findViewById(R.id.selectResidence);
selectResidence.setOnClickListener(this);
case R.id.selectResidence:
selectResidence();
break;
/**
* This method demonstrates how to select a Residence record, identified by
* its primary key, the UUID field.
* Invoking addResidence() writes a Residence record to the database.
* Additionally, it initializes this.residence field.
* The id of this.residence is then used as a parameter in DbHelper.selectResidence.
*/
public void selectResidence()
{
addResidence();
UUID uuid = residence.id;
Residence selectedResidence = app.dbHelper.selectResidence(uuid);
if (residence != null && residence.id.toString().equals(selectedResidence.id.toString()))
{
Toast.makeText(this, "Residence record selected(id: " + residence.id, Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(this, "Failed to select Residence record", Toast.LENGTH_LONG).show();
}
}
Toast and UUID imports are required:
import android.widget.Toast;
import java.util.UUID;
Delete a Residence
In this step, we provide the additional code to delete a single residence from the database.
Layout (xml)
Add a Delete Residence button to the layout:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete Residence"
android:id="@+id/deleteResidence"
android:layout_below="@+id/addResidence"
android:layout_alignParentStart="true"
android:layout_marginTop="42dp"/>
DbHelper
Add this method to DbHelper.java:
public void deleteResidence(Residence residence) {
SQLiteDatabase db = this.getWritableDatabase();
try {
db.delete("tableResidences", "id" + "=?", new String[]{residence.id.toString() + ""});
} catch (Exception e) {
Log.d(TAG, "delete residence failure: " + e.getMessage());
}
}
MyRent (activity)
The following additional items are required:
- A Button field.
- Binding of the button resource in the R file to the new button field.
- Setting a listener on the button.
- Intercepting a button click.
- Implementing a method deleteResidence that in turn invokes DbHelper.deleteResidence.
Here are the code snippets:
private Button deleteResidence;
deleteResidence = (Button) findViewById(R.id.deleteResidence);
deleteResidence.setOnClickListener(this);
@Override
public void onClick(View v)
{
switch (v.getId())
{
...
...
case R.id.deleteResidence:
deleteResidence();
break;
}
}
public void deleteResidence()
{
if (residence == null)
{
addResidence();
}
else {
Residence res = app.dbHelper.selectResidence(residence.id);
app.dbHelper.deleteResidence(res);
}
}
Debug into the app and using adb or otherwise verify that this feature works correctly.
List all residences
In this step we shall select the entire tableResidences record set and store in a List array.
Layout (xml)
<Button
android:id="@+id/selectAllResidences"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/deleteResidence"
android:layout_alignEnd="@+id/selectResidence"
android:text="Select All"/>
DbHelper
/**
* Query database and select entire tableResidences.
*
* @return A list of Residence object records
*/
public List<Residence> selectAllResidences() {
List<Residence> residences = new ArrayList<Residence>();
String query = "SELECT * FROM " + "tableResidences";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
int columnIndex = 0;
do {
Residence residence = new Residence();
residence.id = UUID.fromString(cursor.getString(columnIndex++));
residence.geolocation = cursor.getString(columnIndex++);
columnIndex = 0;
residences.add(residence);
} while (cursor.moveToNext());
}
cursor.close();
return residences;
}
MyRent (activity)
private Button selectAllResidences;
selectAllResidences = (Button) findViewById(R.id.selectAllResidences);
selectAllResidences.setOnClickListener(this);
case R.id.selectAllResidences:
selectAllResidences();
break;
public void selectAllResidences() {
List<Residence> residences = app.dbHelper.selectAllResidences();
Toast.makeText(this, "Retrieved residence list containing " + residences.size() + " records", Toast.LENGTH_LONG).show();
}
Import the List class:
import java.util.List;
Debug into the app to verify that this feature works correctly.
Delete all
In this step we shall delete the entire tableResidences record set.
Layout (xml)
<Button
android:id="@+id/deleteAllResidences"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="49dp"
android:text="Delete All"
android:layout_below="@+id/deleteResidence"
android:layout_alignParentStart="true"/>
DbHelper
/**
* Delete all records
*/
public void deleteAllResidences() {
SQLiteDatabase db = this.getWritableDatabase();
try {
db.execSQL("delete from tableResidences");
} catch (Exception e) {
Log.d(TAG, "delete residences failure: " + e.getMessage());
}
}
Add a method to obtain the number of rows in the database:
/**
* Queries the database for the number of records.
*
* @return The number of records in the dataabase.
*/
public long getCount() {
SQLiteDatabase db = this.getReadableDatabase();
long numberRecords = DatabaseUtils.queryNumEntries(db, TABLE_RESIDENCES);
db.close();
return numberRecords;
}
Required import:
import android.database.DatabaseUtils;
MyRent (activity)
private Button deleteAllResidences;
deleteAllResidences = (Button) findViewById(R.id.deleteAllResidences);
deleteAllResidences.setOnClickListener(this);
case R.id.deleteAllResidences:
deleteAllResidences();
break;
/**
* Delete all records.
* Count the number of rows in database following deletion -should be zero.
* Provide user feed back in a toast.
*/
public void deleteAllResidences() {
app.dbHelper.deleteAllResidences();
Toast.makeText(this, "Number of records in database " + app.dbHelper.getCount(), Toast.LENGTH_LONG).show();
}
Residence model complete
Here will shall add the remaining fields to the Residence model and refactor the database helper appropriately.
Model Residence
package sqlite.myrentsqlite.models;
import java.util.Date;
import java.util.UUID;
public class Residence
{
public UUID id;
public String geolocation;
public Date date;
public boolean rented;
public String tenant;
public double zoom;//zoom level of accompanying map
public String photo;
public Residence()
{
id = UUID.randomUUID();
geolocation = "52.253456,-7.187162";
date = new Date();
rented = false;
tenant = ": none presently";
zoom = 16.0;
photo = "photo";
}
}
DbHelper (Complete)
Note in particular how the Date date, boolean rented and double zoom fields are transformed as they are inserted to and read from the database.
package sqlite.myrentsqlite.app;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import sqlite.myrentsqlite.models.Residence;
public class DbHelper extends SQLiteOpenHelper
{
static final String TAG = "DbHelper";
static final String DATABASE_NAME = "residences.db";
static final int DATABASE_VERSION = 1;
static final String TABLE_RESIDENCES = "tableResidences";
static final String PRIMARY_KEY = "id";
static final String GEOLOCATION = "geolocation";
static final String DATE = "date";
static final String RENTED = "rented";
static final String TENANT = "tenant";
static final String ZOOM = "zoom";
static final String PHOTO = "photo";
Context context;
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTable =
"CREATE TABLE tableResidences " +
"(id text primary key, " +
"geolocation text," +
"date text," +
"rented text," +
"tenant text," +
"zoom text," +
"photo text)";
db.execSQL(createTable);
Log.d(TAG, "DbHelper.onCreated: " + createTable);
}
/**
* @param residence Reference to Residence object to be added to database
*/
public void addResidence(Residence residence) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(PRIMARY_KEY, residence.id.toString());
values.put(GEOLOCATION, residence.geolocation);
values.put(DATE, String.valueOf(residence.date.getTime()));
values.put(RENTED, residence.rented == true ? "yes" : "no");
values.put(TENANT, residence.tenant);
values.put(ZOOM, Double.toString(residence.zoom));
values.put(PHOTO, residence.photo);
// Insert record
db.insert(TABLE_RESIDENCES, null, values);
db.close();
}
public Residence selectResidence(UUID resId) {
Residence residence;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = null;
try {
residence = new Residence();
cursor = db.rawQuery("SELECT * FROM tableResidences WHERE id = ?", new String[]{resId.toString() + ""});
if (cursor.getCount() > 0) {
int columnIndex = 0;
cursor.moveToFirst();
residence.id = UUID.fromString(cursor.getString(columnIndex++));
residence.geolocation = cursor.getString(columnIndex++);
residence.date = new Date(Long.parseLong(cursor.getString(columnIndex++)));
residence.rented = cursor.getString(columnIndex++) == "yes" ? true : false;
residence.tenant = cursor.getString(columnIndex++);
residence.zoom = Double.parseDouble(cursor.getString(columnIndex++));
residence.photo = cursor.getString(columnIndex++);
}
}
finally {
cursor.close();
}
return residence;
}
public void deleteResidence(Residence residence) {
SQLiteDatabase db = this.getWritableDatabase();
try {
db.delete("tableResidences", "id" + "=?", new String[]{residence.id.toString() + ""});
}
catch (Exception e) {
Log.d(TAG, "delete residence failure: " + e.getMessage());
}
}
/**
* Query database and select entire tableResidences.
*
* @return A list of Residence object records
*/
public List<Residence> selectAllResidences() {
List<Residence> residences = new ArrayList<Residence>();
String query = "SELECT * FROM " + "tableResidences";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
int columnIndex = 0;
do {
Residence residence = new Residence();
residence.id = UUID.fromString(cursor.getString(columnIndex++));
residence.geolocation = cursor.getString(columnIndex++);
residence.date = new Date(Long.parseLong(cursor.getString(columnIndex++)));
residence.rented = cursor.getString(columnIndex++) == "yes" ? true : false;
residence.tenant = cursor.getString(columnIndex++);
residence.zoom = Double.parseDouble(cursor.getString(columnIndex++));
residence.photo = cursor.getString(columnIndex++);
columnIndex = 0;
residences.add(residence);
} while (cursor.moveToNext());
}
cursor.close();
return residences;
}
/**
* Delete all records
*/
public void deleteAllResidences() {
SQLiteDatabase db = this.getWritableDatabase();
try {
db.execSQL("delete from tableResidences");
} catch (Exception e) {
Log.d(TAG, "delete residences failure: " + e.getMessage());
}
}
/**
* Queries the database for the number of records.
*
* @return The number of records in the dataabase.
*/
public long getCount() {
SQLiteDatabase db = this.getReadableDatabase();
long numberRecords = DatabaseUtils.queryNumEntries(db, TABLE_RESIDENCES);
db.close();
return numberRecords;
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists " + TABLE_RESIDENCES);
Log.d(TAG, "onUpdated");
onCreate(db);
}
}
Update
In this the final step we shall update a tableResidences record - a Residence object.
Layout (xml)
<Button
android:id="@+id/updateResidence"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Update"
android:layout_alignTop="@+id/deleteAllResidences"
android:layout_alignEnd="@+id/selectAllResidences"/>
DbHelper
/**
* Update an existing Residence record.
* All fields except record id updated.
*
* @param residence The Residence record being updated.
*/
public void updateResidence(Residence residence) {
SQLiteDatabase db = this.getWritableDatabase();
try {
ContentValues values = new ContentValues();
values.put(GEOLOCATION, residence.geolocation);
values.put(DATE, String.valueOf(residence.date.getTime()));
values.put(RENTED, residence.rented == true ? "yes" : "no");
values.put(TENANT, residence.tenant);
values.put(ZOOM, Double.toString(residence.zoom));
values.put(PHOTO, residence.photo);
db.update("tableResidences", values, "id" + "=?", new String[]{residence.id.toString() + ""});
} catch (Exception e) {
Log.d(TAG, "update residences failure: " + e.getMessage());
}
}
MyRent (activity)
private Button updateResidence;
updateResidence = (Button) findViewById(R.id.updateResidence);
updateResidence.setOnClickListener(this);
case R.id.updateResidence:
updateResidence();
break;
/**
* Update a residence record.
* Create and insert a test record.
* Make some changes to its fields and update its copy in the database.
* Verify and provide toast feedback.
*/
public void updateResidence() {
addResidence(); // This initializes the instance variable Residence residence
Residence res = app.dbHelper.selectResidence(residence.id);
// Makes some distinguishing changes to res fields
res.tenant = "Barney Gumble";
res.rented = true;
res.zoom = 20;
app.dbHelper.updateResidence(res);
// Read the updated rrow and verify it's correct.
Residence res2 = app.dbHelper.selectResidence(res.id);
boolean b = res.zoom == res2.zoom;
if (b == true) {
Toast.makeText(this, "Update succeeded", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(this, "Update failed", Toast.LENGTH_LONG).show();
}
}
A completed version of the application is available to download from GitHub: MyRentSQLite
Exercises
(1) Use this lab to integrate an SQLite database in MyRent app.
(2 )Add a feature to DbHelper to insert a list of Residence records.
Presently a method exists to insert a single record. Extend the:
- UI (add a button)
- MyRent activity (add an event handler)
- DbHelper (add residences method).
Android Debug Bridge (adb)
adb is a commandline tool to view and manipulate SQlite databases generated within an Android app.
Here is the link for official Android documentation: Android Debug Bridge
In this step we will:
very briefly describe how modify the path environment variable on your computer (Mac & Windows) by adding the path to the Android Debug Bridge utility (adb).
outline how to manually delete the database data using adb
Add Android Debug Bridge to the PATH variable
- On the Mac (OSX)
The Android Debug Bridge (adb) is located in the platform-tools folder in the ADT bundle.
It is necessary to insert the path to adb on the PATH environment variable.
The path to this utility might be something like the following (amend appropriately for your particular environment):
$HOME/android-dev/adt-bundle-mac-x86_64-20130729/sdk/platform-tools
In OSX this can be added to the PATH variable by editing the .bash_profile file which is located in the home folder. Quoting from, for example, OSX Mountain Lion support page :
In Windows 10, a typical path to adb.exe is as follows:
C:\Users\User\AppData\Local\Android\sdk\platform-tools
The home folder stores your documents, preference settings, and other information. A home folder is created for each user of your computer when his or her account is set up. If you are the only user of your computer, there is only one home folder. The home folder isn’t actually named “Home”; its name is the same as the account name specified in your user account. Your home folder appears in the sidebar of Finder windows.
See also OSX El Capitan: home folder.
Open a terminal window. Check that you are in the home folder. Use Sublime Text editor to open .bash_profile*
The first line of the modified path could be this:
PATH=\$PATH:/\$HOME/android-dev/adt-bundle-mac-x86_64-20130729/sdk/platform-tools:\
- On Windows
On Windows you may edit the path by accessing
System Properties > Advanced > Environment Variables
Using adb
In a terminal window execute
adb shell
This will change the command prompt to root@generic:/ ... .
Change directory:
cd data/data
Type *ls sqlite.myrentsqlite.
You should see something like that shown in Figure 1 :
To remove the database execute
rm -rf sqlite.myrentsqlite/databases
It's important to note that the name of the folder containg the database, sqlite.myrentsqlite , derives from the package name in the AndroidManifest.xml file and that the name of the database, residences.db, is that which we have assigned in DbHelper.java. The table, tableResidences, will also have been assigned in DbHelper.
SQLite Browser
A third-party SQLite browser provides an alternative approach to adb to view the database content.
Detailed information on the installation and use of the browser is contained in the stackoverflow article View contents of database file in Android Studio, summarized in the the following screenshots: