Data Persistence

Persisting data is an important topic in application development

  • because users typically expect to reuse data in the future

For Android, there are primarily three basic ways of persisting data:

  • A lightweight mechanism known as shared preferences to save small chunks of data
  • Traditional file systems
  • A relational database management system through the support of SQLite databases

SharedPreferences

If you have data that can be represented using name/value pairs, then use the SharedPreferences object

For example, if you want to store user preference data such as username, background color, date of birth, or last login date, then the SharedPreferences object is the ideal way to store this data

Android provides the SharedPreferences object to help you save simple application data.

  • SharedPreferences allow you to share data across multiple apps

There are 2 ways to use SharedPreferences:

  • Use the PreferenceActivity class to create preferences and modify data during runtime
  • Programmatically retrieving and modifying the preferences values using the SharedPreferences class

Creating SharedPreferences

Programmatically retrieving and modifying the preferences values using the SharedPreferences class

Define SharedPreferences

1
2
3
public static int MODE = Context.MODE_PRIVATE;
public static final String PREFERENCE_NAME = "SaveSetting";
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);

Save SharedPreferences

1
2
3
4
5
6
7
8
9
10
private void savePreferences(){
//Open the sharedPreferences editor and save
SharedPreferences.Editor editor = sharedPreferences.edit();

//Key value pairs
editor.putString("Name", "Vines");
editor.putInt("Age", 18);
editor.putFloat("Height", 1.71f);
editor.apply();
}

Data is stored in xml format, located at /data/data/<package name>/shared_prefs/SaveSetting.xml.

Or just type “Device File Explorer” in “Help”.

Load SharedPreferences

1
2
3
4
5
6
7
8
9
private void showPreferences(){
//comment below if you have declared the sharedPreference as the class variable
//SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);

//Second param: Return that default value when there is no matching key.
String name = sharedPreferences.getString("Name", "DefaultName");
int age = sharedPreferences.getInt("Age", -1);
float height = sharedPreferences.getFloat("Height", -1f)
}

Share data across multiple Apps

To allow the access of SharedPreferences of another app, 3 conditions must be satisfied:

  • The MODE of the Preferences is MODE_PRIVATE
    • the default mode, the created file can only be accessed by the calling application or all applications sharing the same user ID.
  • The visitor must know the package name and SharedPreferences name to access via Context, and use the same sharedUserID
  • The visitor must know the name and type of every data to retrieve
  • All the Shared Apps must use the same sharedUserID in the AndroidManifest.xml
1
2
3
4
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app1"
android:sharedUserId="com.example.shared_id">
<!--android:sharedUserId need be the same for all the app you wanted to share-->
1
2
3
4
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app2"
android:sharedUserId="com.example.shared_id">
<!--android:sharedUserId need be the same for all the app you wanted to share-->

You may need to uninstall the app after you change the sharedUserId.

Define SharedPreferences to Access another App

  • We need to match the PREFERENCE_NAME and PREFERENCE_PACKAGE of the another App when accessing
1
2
3
4
public static int MODE = Context.MODE_PRIVATE;
public static final String PREFERENCE_NAME = "SaveSetting";
public static final String PREFERENCE_PACKAGE = "com.example.shared_id";
SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);

Access via Context in the OnCreate Method

Since we are not in the same context, we need to access the context of another app.

  • Add this in the onCreate() method.
1
2
3
4
5
6
7
8
9
Context c = null;
try{
c = this.createPackageContext(PREFERENCE_PACKAGE, CONTEXT_IGNORE_SECURITY);
}catch (PackageManager.NameNotFoundException e){
e.printStackTrace();
}

SharedPreferences sharedPreferences = c.getSharedPreferences(PREFERENCE_NAME, MODE);
//Try to get the values...

Internal and External Storage

The SharedPreferences object enables you to store data that is best stored as name/value pairs

However, sometimes you might prefer to use the traditional file system to store your data

For example, you might want to store the text of poems you want to display in your applications

  • In Android, you can use the classes in the java.io package to do so.
  • java.io allows Persisting Data to Files.

Internal Storage

If you need to store ad-hoc data then using the internal storage is a good option.

For example, your application (such as an RSS reader) might need to download images from the web for display.

In this scenario, saving the images to internal storage is a good solution.

You might also need to persist data created by the user, such as when you have an application that enables users to take notes and save them for later use.

Store private data on the device memory, in directory /data/data/<package name>/files

  • Cannot be accessed by other apps
  • only available on the own app
  • When uninstall the app, files will also be removed.

The 2 commonly used functions:

  • openFileOutput()
  • openFileInput()

Internal Storage – Save

  • To save text into a file, you use the FileOutputStream class.
  • The openFileOutput() method opens a named file for writing, with the mode specified
1
FileOutPutStream fout = openFileOutput("myText.txt", MODE_PRIVATE);
  • MODE_PRIVATE constant is to indicate that the created file can only be accessed by the calling application

    • As long as you use MODE_PRIVATE for your files on the internal storage, they are never accessible to other apps
    • The other mode options have been deprecated since API level 17
  • To convert a character stream into a byte stream, you use an instance of the OutputStreamWriter class, by passing it an instance of the FileOutputStream object

1
2
3
4
5
6
7
OutputStreamWriter osw = new OutputStreamWriter(fout);
//write() method to write the string to the file
osw.write(str);
//To ensure that all the bytes are written to the file, use the flush() method
osw.flush();
//Finally, use the close() method to close the file
osw.close();

An example of Saving data to an internal file:

1
2
3
4
5
6
7
8
9
10
11
public void writeData(String str){
try{
FileOutputStream fout = openFileOutput("myText.txt",MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(fout);
osw.write(str);
osw.flush();
osw.close();
}catch (IOException e){
e.printStackTrace();
}
}

You can find the myText.txt in directory /data/data/<package name>/files using “Device File Explorer”.

Internal Storage – Read

To read the content of a file:

  • Use the FileInputStream class, together with the InputStreamReader class
1
2
FileInputStream fin = openFileInput("myText.txt");
InputStreamReader isr = new InputStreamReader(fin);

openFileInput method opens a private file associated with this Context’s application package for reading and it does not require any mode

Because you do not know the size of the file to read,

  • the content is read in blocks of 100 characters into a buffer (character array)
  • the characters read are then copied into a String object
1
2
3
4
5
6
7
8
9
10
//Assign READ_BLOCK_SIZE = 100 somewhere else

char [] inputBuffer = new char[READ_BLOCK_SIZE];
String s = "";
int charRead;
while((charRead = isr.read(inputBuffer)) > 0){
String readString = String.copyValueOf(inputBuffer, 0, charRead);
s += readString;
inputBuffer = new char[READ_BLOCK_SIZE];
}

The read() method of the InputStreamReader object checks the number of characters read and returns –1 if the end of the file is reached

An example of Reading data from an internal file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public String readData(String fileName){
try{
FileInputStream fin = openFileInput(fileName);
InputStreamReader isr = new InputStreamReader(fin);
char [] inputBuffer = new char[100];
String s = "";
int charRead;
while((charRead = isr.read(inputBuffer)) > 0){
String readString = String.copyValueOf(inputBuffer, 0, charRead);
s += readString;
inputBuffer = new char[100];
}
return s;
}catch (IOException e){
e.printStackTrace();
}
return null;
}

Other Useful APIs

  • getFilesDir()
    • Gets the absolute path to the filesystem 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.

External Storage

There are times when you need to share your application data with other users

For example, you might create an Android application that logs the coordinates of the locations that a user has been to, and subsequently, you want to share all this data with other users

In this scenario, you can store your files on the SD card of the device so that users can easily transfer the data to other devices (and computers) for use later.

It would be useful to save data to external storage (such as an SD card).

  • larger capacity
  • larger capability to share the files easily with other users

All files are in the SD card can be:

  • globally read

Note we need to check the availabliity using Environment.getExternalStorageState()

  • Because External storage can be unmounted by users

External Storage – Getting the path

First we need to find out the directory of the SD card.

  • getExternalStorageDirectory() method returns the full path to the external storage
  • Typically, it should return the “/sdcard” path for a real device, and “/mnt/sdcard” for an Android emulator
  • Never try to hardcode the path of the SD card
    • manufacturers may choose to assign a different path name to the SD card
1
2
3
4
5
6
File sdCard = Environnment.getExternalStorageDirectory();
File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");
//Create a folder called "MyFiles" in your SD card
directory.mkdirs();
//Create a file called "myText.txt" inside the folder
File file = new File(directory, "myText.txt");

External Storage - Save

The idea is same as Internal Storage but this time we save into a SD card.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void writeData(String str){
try{
File sdCard = Environnment.getExternalStorageDirectory();
File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");
directory.mkdirs();
File file = new File(directory, "myText.txt");

FileOutputStream fout = openFileOutput("myText.txt",MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(fout);
osw.write(str);
osw.flush();
osw.close();
}catch (IOException e){
e.printStackTrace();
}
}

External Storage - Read

The idea is same as Internal Storage but this time we read from a SD card.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public String readData(String fileName){
try{
File sdCard = Environnment.getExternalStorageDirectory();
File directory = new File(sdCard.getAbsolutePath() + "/MyFiles");
File file = new File(directory, fileName);

FileInputStream fin = openFileInput(fileName);
InputStreamReader isr = new InputStreamReader(fin);
char [] inputBuffer = new char[100];
String s = "";
int charRead;
while((charRead = isr.read(inputBuffer)) > 0){
String readString = String.copyValueOf(inputBuffer, 0, charRead);
s += readString;
inputBuffer = new char[100];
}
return s;
}catch (IOException e){
e.printStackTrace();
}
return null;
}

SQLite database

For saving relational data, using a database is much more efficient

For example, if you want to store the test results of all the students in a school, it is much more efficient to use a database to represent them because you can use database querying to retrieve the results of specific students.

Moreover, using databases enables you to enforce data integrity by specifying the relationships between different sets of data

Android uses the SQLite database system

  • The database that you create for an application is only accessible to itself;
  • other applications will not be able to access it

SQLite:

  • Self-contained
  • Serverless
  • Zero-configuration
  • Transactional: Atomic, Consistent, Isolated, Durable
  • Can run on Windows, Linux, Unix, Mac OS, and embedded OS (e.g., Android, iOS, Palm OS, Symbian, Windows Mobile, etc.)

Create Helper class to encapsulate all the complexities

A good practice for dealing with databases is to create a helper class to encapsulate all the complexities of accessing the data so that it is transparent to the calling code.

In order to use the Database, we usually develop an DBAdapter class.

  • A DBAdapter class creates, opens, closes, and uses a SQLite database and hide the implementation from the user.

Before Creating database, we need to declare some constant.

the DATABASE_CREATE constant contains the SQL statement for creating the contacts table within the MyDB database.

Constructor of DBAdapter class

1
2
3
4
5
public DBAdapter(Context ctx)
{
this.context = ctx;
DBHelper = new DatabaseHelper(context);
}

The constructor of the DBAdapter class will then create an instance of the DatabaseHelper class to create a new database

Within the DBAdapter class, a private class that extends the SQLiteOpenHelper class is used

  • SQLiteOpenHelper is a helper class in Android to manage database creation and version management
  • The onCreate() and onUpgrade() methods must be overriden
1
2
3
4
5
6
private static class DatabaseHelper extends SQLiteOpenHelper{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void onCreate(SQLiteDatabase db){
try{
db.execSQL(DATABASE_CREATE);
}
catch (SQLException e){
e.printStackTrace();
}
}


@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS contacts");
onCreate(db);
}

Database operation methods

1
2
3
4
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME , name);
initialValues.put(KEY_EMAIL , email);
db.insert(DATABASE_TABLE, null, initialValues);

In the Insert function, we specify nullColumnHack parameter as null because SQL doesn’t allow inserting a completely empty row without naming at least one column name. If your provided values is empty, no column names are known and an empty row can’t be inserted.

If not set to null, the nullColumnHack parameter provides the name of nullable column name to explicitly insert a NULL into in the case where your values is empty.

To Use the Helper Class

Add a contact to the table

1
2
3
4
5
//add one contact to the table
db.open(); //db is the helper class object
long id = db.insertContact("Sam", "sam@gmail.com");
id = db.insertContact("Peter", "peter@gmail.com");
db.close()

Retrieving all contacts from a table using Cursor class

1
2
3
4
5
6
7
8
9
//retrieving all contacts from a table
db.open();
Cursor c = db.getAllContacts();
if(c.moveToFirst()){
do{
DisplayContact(c);
} while (c.moveToNext());
}
db.close();

Retrieving a contact from a table

1
2
3
4
5
6
7
8
9
10
db.open();
c = db.getContact(2);
if (c.moveToFirst()){
DisplayContact(c);
}
else
{
Toast.makeText(this, "No Contact found", Toast.LENGTH_SHORT).show();
}
db.close();

Updating a contact in a table

Deleting a contact from a table

Cursor class as return value for queries

Android uses the Cursor class as a return value for queries.

  • Think of the Cursor as a pointer to the result set from a database query.
  • Using Cursor enables Android to more efficiently manage rows and columns as needed
  • You use a ContentValues object to store name/value pairs. Its put() method enables you to insert keys with values of different data types.

Some common functions of Cursor:

  • moveToFirst()
    • Move the cursor to the first entry. This method will return false if the cursor is empty.
  • moveToNext()
    • Move the cursor to the next entry
  • moveToPrevious()
    • Move the cursor to the previous entry
  • getCount()
    • Get the number of rows in the cursor
  • getColumnIndexOrThrow()
    • Returns the zero-based index for the given column name, or throws IllegalArgumentException if the column doesn’t exist
  • getColumnName()
    • Returns the column name at the given zero-based column index
  • getColumnNames()
    • Returns a string array holding the names of all of the columns in the result set
  • getColumnIndex()
    • Returns the zero-based index for the given column name, or -1 if the column doesn’t exist
  • moveToPosition()
    • Move the cursor to an absolute position
  • getPosition()
    • Returns the current position of the cursor in the row set
1
2
3
4
5
6
//Loop through Cursor:
for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {

}

c.close();
1
2
3
4
5
6
7
8
9
10
11
12
13
//Loop through the Cursor (another way):

int cCount = c.getCount();
if(cCount > 0 && c.moveToFirst()){
for(int i = 0; i < cCount; i++){

//Do something...

c.moveToNext();
}
}

c.close();

Content Provider

One of Android’s 4 basic components

Content provider is the recommended way to share data across packages and applications

  • Allow Sharing of Database to other applications.

The Concept of Content Provider

Think of a content provider as a data store

  • How it stores its data is not relevant to the application using it
  • However, the way in which packages can access the data stored in it using a consistent programming interface is important

A content provider behaves very much like a database

  • you can query it, edit its content, and add or delete content
  • However, unlike a database, a content provider can use different ways to store its data. The data can be stored in a database, in files, or even over a network

In the previous SQLite part, the application and the database are directly connected by the db object.

However, In Content Provider part , We use Content Provider to connect with the database.

The common Content Providers

Android ships with many useful content providers, including the following:

  • Browser
    • Stores data such as browser bookmarks, browser history, and so on
  • CallLog
    • Stores data such as missed calls, call details, and so on
  • Contacts
    • Stores contact details
  • MediaStore
    • Stores media files such as audio, video, and images
  • Settings
    • Stores the device’s settings and preferences

Basic Idea

Data operation functions (insert, delete, update, etc.) are implemented in the ContentProvider class to documents, database or network

  • These functions in ContentProvider are called indirectly via the ContentResolver class with URI
  • Each data is represented by an REST style URI

Besides the many built-in content providers, you can also create your own content providers

URI (Uniform Resource Identifier)

You can think of URI is a Table like in SQL.

To query a content provider, you specify the query string in the form of a Uniform Resource Identifier (URI), with an optional specifier for a particular row.

  • Here’s the format of the query URI: <standard_prefix>://<authority>/<data_path>/<id>
  • standard prefix : content://
    • The standard prefix for content providers is always content://
  • authority : specifies the name of the content provider
    • e.g. contacts for the bulit-in Contacts content provider
  • data_path : specifies the kind of data requested
    • e.g. content://contacts/peoeple - all contacts in the Contacts content provider
  • id : specifies the specific record requested
    • e.g. content://contacts/peoeple/2 - contact number 2 in the Contacts content provider

Some examples

most of them are defined as constant under the package android.provider.*

Using a Content Provider

For Example, we want to retrieve the contacts stored in Contacts application and display them in the ListView.

First we need to declare the URI for accessing the Contacts application(i.e. declare the table we want to access)

1
Uri allContacts = ContactsContract.Contacts.CONTENT_URI;

Then we need to check if that app has permission to access the Contacts.

  • If there is no permission yet, we need to request permission.
1
2
3
4
5
6
7
8
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
REQUEST_READ_CONTACTS);
} else {
//Do something...
}

To access the Contacts application, you need to have the READ_CONTACTS permission in your AndroidManifest.xml file

1
2
3
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.app1">
<uses-permission android:name="android.permission.READ_CONTACTS"/>

Use CursorLoader to perform Cursor query

CursorLoader is an Android API that is used to interact with a ContentProvider asynchronously. By asynchronously I mean, it can do the query in a background thread without blocking the main thread (also called the UI thread). After querying, it will retrieve the result from ContentProvider and reconnect to the Activity on the main thread.

The CursorLoader class performs the cursor query on a background thread and therefore does not block the application UI

CursorLoader is only available beginning with Android API level 11 and later

Firstly, perform the query to get the table with CursorLoader.

1
2
3
4
5
6
7
8
Cursor c;
CursorLoader cursorLoader = new CursorLoader(this,
allContacts,
null,
null,
null,
null};
c = cursorLoader.loadInBackground();

The SimpleCursorAdapter object maps a cursor to TextViews (or ImageViews) defined in your XML file (activity_main.xml). It maps the data (as represented by columns) to views (as represented by views):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
String[] columns = new String[]{ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts._ID};

int[] views = new int[]{R.id.TVName, R.id.TVID};
SimpleCursorAdapter adapter;

adapter = new SimpleCursorAdaptor(this,
R.layout.activity_main,
c,
columns,
views,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
this.setListAdapter(adapter);

To Perform Different Queries

The CursorLoader parameters:

new CursorLoader( context, URI, projection, selection, selectionArgs, sortOrder);

  • URI - FROM table
  • projection - SELECT Columns to Return
  • selection - WHERE clause
  • selectionArgs - WHERE clause value substitution
  • sortOrder - SORT BY

Projection

  • the _ID, DISPLAY_NAME, and HAS_PHONE_NUMBER fields are retrieved
1
2
3
4
5
6
7
8
9
10
11
12
String[] projection = new String[]{ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER};

Cursor c;
CursorLoader cursorLoader = new CursorLoader(this,
allContacts,
projection,
null,
null,
null};
c = cursorLoader.loadInBackground();

Filtering

  • The selection and selectionArgs parameters for the CursorLoader class enable you to specify a SQL WHERE clause to filter the result of the query
    • selectionArgs will replace the ? in selection
1
2
3
4
5
6
7
8
Cursor c;
CursorLoader cursorLoader = new CursorLoader(this,
allContacts,
projection,
ContactsContract.Contacts.DISPLAY_NAME + "LIKE ?",
new String[] {"%Lee"},
null};
c = cursorLoader.loadInBackground();

Or we can use the selection only, selectionArgs remain null:

1
2
3
4
5
6
7
8
Cursor c;
CursorLoader cursorLoader = new CursorLoader(this,
allContacts,
projection,
ContactsContract.Contacts.DISPLAY_NAME + "LIKE '%Lee'",
null,
null};
c = cursorLoader.loadInBackground();

Sorting

  • The sortOrder parameter of the CursorLoader class enables you to specify a SQL ORDER BY clause to sort the result of the query
1
2
3
4
5
6
7
8
Cursor c;
CursorLoader cursorLoader = new CursorLoader(this,
allContacts,
projection,
ContactsContract.Contacts.DISPLAY_NAME + "LIKE ?",
new String[] {"%Lee"},
ContactsContract.Contacts.DISPLAY_NAME + " ASC"};
c = cursorLoader.loadInBackground();

Create your own Content Providers

Creating your own content provider in Android is relatively simple

  • Inherit the abstract ContentProvider class
  • Override the various methods defined within it
    • onCreate(), query(), getType(), insert(), delete(), and update()
  • Add description in AndroidManifest.xml

Create Content Provider

Declare CONTENT_URI and implement UriMatcher to determine URI for single entry and multiple entries

The “code” is returned when a URI is matched against the given components via the match() function

1
public void addURI (String authority, String path, int code)

When using UriMatcher, the match() function can be called to determine the URI type (e.g., multiple entries or single entry)

1
2
3
4
5
6
7
8
9
10
switch(uriMatcher.match(uri)){ 
case MULTIPLE_PEOPLE:
// Process for multiple data entries
break;
case SINGLE_PEOPLE:
// Process for single data entry
break;
default:
throw new IllegalArgumentException("Not supported URI:" + uri);
}

Register Content Provider

  • Let the System know you have a provider so other application can use it
  • Register Content Provider in AndroidManifest.xml
  • Register with the <provider> tag
1
2
3
<provider android:name = ".PeopleProvider"
android:authorities = "edu.polyu.peopleprovider"
android:exported="true" />

The above registered a content provider instance called PeopleProvider with authority edu.polyu.peopleprovider

Content Resolver

Content Provider provides an interface to query content.

Content Resolver resolves a URI to a specific Content provider.

The way to query a content provider is contentResolverInstance.query(URI,.....)

ContentProvider is called via ContentResolver with URI.

1
ContentResolver resolver = getContentResolver();

Content Provider - Query

Once ContentResolver is acquired, the query() function can be used to obtain the target data set

Below is a query for data ID = 2 (where it is defined in the URI)

1
2
3
4
5
6
7
8
9
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse(CONTENT_URI_STRING + "/" + "2");

//We need Cursor to get the query
Cursor cursor = resolver.query(uri,
new String[] {KEY_ID, KEY_NAME, KEY_AGE, KEY_HEIGHT},
null,
null,
null);

  • uri defines the data set to query
  • projection defines the list of columns to return
  • selection and selectionArgs define the query criteria
  • sortOrder defines how the rows are sorted

Content Provider - Insert

Use Insert() to add single data entry or bulkInsert() to add multiple data entries

Example of Insert()

1
2
3
4
5
ContentValues values = new ContentValues();
values.put(KEY_NAME, "Tom");
values.put(KEY_AGE, 21);
values.put(KEY_HEIGHT, 175);
Uri newUri = resolver.insert(CONTENT_URI, values);

Example of bulkInsert()

1
2
3
ContentValues[] arrayValues = new ContentValues[10];
//define the value in every ContentValuess
int count = resolver.bulkInsert(CONTENT_URI, arrayValues)

Content Provider - Delete

Use delete() to erase entries

  • To erase a single entry, the data ID can be defined in the URI
  • To erase multiple entries, the criteria can be defined in selection
1
resolver.delete(uri, where, selectionArgs);

Example: Delete data with ID=2

1
2
Uri uri = Uri.parse(CONTENT_URI_STRING + "/" + "2");
int result = resolver.delete(uri, null, null);

Example: Delete data with ID>4 with selection

1
2
String selection = KEY_ID + ">4";
int result = resolver.delete(CONTENT_URI, selection, null);

Content Provider - Update

Use update() to edit entries

  • The ID of the data entry to update can be defined in the URI
  • Condition to update can be defined in selection (3rd parameter)
1
resolver.update(uri, values, where, selectionArgs);

Example: Update data with ID=7

1
2
3
4
5
6
ContentValues values = new ContentValues();
values.put(KEY_NAME, "Tom");
values.put(KEY_AGE, 21);
values.put(KEY_HEIGHT, 183);
Uri uri = Uri.parse(CONTENT_URI_STRING + "/" + "7");
int result = resolver.update(uri, values, null, null);