Mobile Programming Lecture 10 - Florida State...

Post on 04-Jul-2020

2 views 0 download

Transcript of Mobile Programming Lecture 10 - Florida State...

Mobile ProgrammingLecture 10

ContentProviders

Lecture 9 Review

● In creating a bound service, why would you choose to use a Messenger over extending Binder?

● What are the differences between using GPS provider and Network provider?

● When should you stop listening for location updates? Why at that point?

● How would you implement turn-by-turn directions?

● When should you disable a Sensor?

Lecture 9 Review

● How do you start an Activity B from and Activity A, and get a result back from Activity B when B has completed?

● How can you find out the structure of the intent filter for a given intent in the system?

Agenda

● ContentProviders○ Querying existing databases

○ Creating a database for your app

○ Inserting data

○ Updating data

○ Deleting data

○ Content provider permissions

● Viewing ContentProvider data

Android Application Components

1. Activity

2. Broadcast Receiver

3. Content Provider

4. Service

Content Provider Basics

● A Content Provider manages access to a central repository of data

● Content providers are primarily intended to be used by other applications, which access the provider using a provider client object

● A Content Provider presents data to external applications as one or more tables that are similar to the tables found in a relational database

Content Provider Basics

● When you want to access data in a Content Provider, you use the ContentResolver object in your application's Context to communicate with the provider as a client

● The ContentResolver object communicates with the provider object, an instance of a class that implements ContentProvider

● The provider object receives data requests from clients, performs the requested action, and returns the results.

Content Provider Basics

● You don't need to develop your own provider if you don't intend to share your data with other applications, instead○ Use SharedPreferences

● The reason you use a ContentProvider is ○ Data is too complex for SharedPreferences○ Expose your data to other applications

Content Provider Basics

● _ID column serves as the primary key column that the Content Provider automatically maintains

● Here's an example of a table with an _ID column

word app id frequency locale _ID

mapreduce user1 100 en_US 1

precompiler user14 200 fr_FR 2

applet user2 225 fr_CA 3

const user1 255 pt_BR 4

int user5 100 en_UK 5

Contacts ContentProvider

In our examples, we will look at the Contacts ContentProvider

A lot of the work for a query goes into reading the documentation online

http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html

Requesting Permission

In order to read the user's contacts, you need to request permission first

android.permission.READ_CONTACTS

Constructing a QueryLet's build several queries for ContractsContract.ContactsThe columns can be found in the documentation hereA few of the columns are ...

_ID long

LOOKUP_KEY String

NAME_RAW_CONTACT_ID long

DISPLAY_NAME_PRIMARY String

PHOTO_ID long

PHOTO_URI long

IN_VISIBLE_GROUP int

HAS_PHONE_NUMBER int

TIMES_CONTACTED int

Constructing a QueryWe will use the following fields in our class in our examples

public class ContactsContractExampleActivity extends ListActivity {

Cursor mCursor;

CursorAdapter mCursorAdapter;

String[] mProjection;

String[] mListColumns;

String mSelectionClause;

String[] mSelectionArgs;

String mOrderBy;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

}

}

Constructing a QueryWe will use the following fields in our class in our examples

public class ContactsContractExampleActivity extends ListActivity {

Cursor mCursor;

CursorAdapter mCursorAdapter;

String[] mProjection;

String[] mListColumns;

String mSelectionClause;

String[] mSelectionArgs;

String mOrderBy;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

}

}

Note that we're extending ListActivity, so we don't need to add a ListView to our XML layout file. We don't even need an XML layout file

Constructing a Query

Consider the following SQL queries

Constructing a Query - Query 1

SELECT * FROM ContactsContract.Contacts

"Get every column for every contact in this database table"

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

When you want to access data in a content provider, you need to use a ContentResolver. You can get the ContentResolver by calling getContentResolver()

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

It returns a Cursor object.

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Using a Cursor object, you can call the query() method to execute a query on a content provider.

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

The second argument is a String array (i.e. String[ ]) of which columns we want to be returned by the query. Passing null means return all columns, i.e. SELECT *

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

The first argument to Cursor.query() is a Uri. It specifies the table that you want to access, i.e. SELECT * FROM table

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

ContactsContract is a content provider. You can think of it as the database

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

ContactsContract.Contacts is a content provider. You can think of it as a table in the database

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

This is one of the Uris for the table, which says how you want to access the table. Some tables have multiple Uris

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

The third argument is a String. Here you specify the conditions for your query. Passing null means don't specify any conditions

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

The fourth argument is a String[ ]. We will get back to this soon

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

The fifth argument is a String. It says how we want to sort our results. Passing null means don't specify any sorting

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

SELECT * FROM ContactsContract.Contacts

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Our query is now complete, and the Cursor can iterate through the results. But since we want to attach our results to a ListView, we need to add a few more lines of code

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Although our query was on all columns, here we create a String array of the columns we want to have displayed in our ListView.

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

The column names are usually constants that you can reference via the database table

Constructing a Query - Query 1

● In order to setup our ListView properly, we need to create an XML layout file that can represent each row in the list.

● We create a Layout XML file called query1.xml, which has the following TextView

Constructing a Query - Query 1<?xml version="1.0" encoding="utf-8"?>

<TextView

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/contact_name"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Large Text"

android:textAppearance="?android:attr/textAppearanceLarge" />

Constructing a Query - Query 1

<?xml version="1.0" encoding="utf-8"?>

<TextView

xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/contact_name"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Large Text"

android:textAppearance="?android:attr/textAppearanceLarge"/>

Note the android:id attribute of the TextView

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

So, String[ ] mListColumns specifies which columns we want to select

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

and int[] mListItems is a corresponding array, telling us where to place the actual value of the DISPLAY_NAME

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

It will be placed in this TextView, whose android:id="@+id/contact_name"

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

We've been using ArrayAdapters with ListViews in the past, but here we use a SimpleCursorAdapter instead, because we have a Cursor (i.e. mCursor)

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

First argument is a Context

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Second argument is our Layout XML file resource used to construct the ListView

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Third argument is our Cursor object

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Fourth argument is our String array of column names

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Fifth argument is our int array of TextView resources

Constructing a Query - Query 1@Override

public void onCreate(Bundle savedInstanceState) {

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, null, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns,

mListItems);

setListAdapter(mCursorAdapter);

}

Finally, we call setListAdapter and pass our SimpleCursorAdapter

Constructing a Query - Query 1

See the query1() method inside of ContactsContractQueryExample.tar

This query is inefficient, because we're requesting all columns, but yet only using one column after we get the results

Constructing a Query - Query 2

Consider the following SQL query

SELECT _ID, DISPLAY_NAME FROM ContactsContract.Contacts

"Get the _ID and DISPLAY_NAME for all contacts"

Constructing a Query - Query 2@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts. _ID,

ContactsContract.Contacts. DISPLAY_NAME };

mCursor = getContentResolver().query(

ContactsContract.Contacts. CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts. DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter( this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Constructing a Query - Query 2@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Here we make a String array of the columns that we need.

Constructing a Query - Query 2@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Instead of passing null, we pass our String array of column names

Constructing a Query - Query 2@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mCursor = getContentResolver(). query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

SELECT _ID, DISPLAY_NAMEFROM ContactsContract.Contacts

Constructing a Query - Query 2@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

This hasn't changed

Constructing a Query - Query 2

See the query2() method inside of ContactsContractQueryExample.tar

Constructing a Query - Query 3

Consider the following SQL query

SELECT _ID, DISPLAY_NAME FROM ContactsContract.Contacts WHERE HAS_PHONE_NUMBER = 1

"Get the _ID and DISPLAY_NAME for all contacts that have phone numbers"

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts. _ID,

ContactsContract.Contacts. DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts. HAS_PHONE_NUMBER +

" = ?";

mSelectionArgs = new String[]{ "1"};

mCursor = getContentResolver().query(

ContactsContract.Contacts. CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts. DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter( this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.DISPLAY_NAME + " = ? ";

mSelectionArgs = new String[]{"Fred"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

mProjection has not changed

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Here we use "?" as a placeholder. ContactsContract.Contacts.HAS_PHONE_NUMBER is a String, so we're appending " = ?" to this String0

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Each "?" will be replaced by an element in this String array, sequentially. In this case we only have one "?"

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Now instead of passing null for the selection clause, we pass our mSelectionClause String

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Instead of passing null, we pass our selection args array mSelectionArgs

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mCursor = getContentResolver(). query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

SELECT _ID, DISPLAY_NAME FROM ContactsContract.ContactsWHERE HAS_PHONE_NUMBER = 1

Constructing a Query - Query 3@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection, null, null,

null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

The ? is a placeholder here, just as %d or %s is a placeholder when you call printf()

Constructing a Query - Query 3

See the query3() method inside of ContactsContractQueryExample.tar

Constructing a Query - Query 4

Consider the following SQL query

SELECT _ID, DISPLAY_NAME, TIMES_CONTACTED FROM ContactsContract.Contacts

WHERE HAS_PHONE_NUMBER = 1

AND TIMES_CONTACTED > 5

"Get the _ID and DISPLAY_NAME for all contacts that have a phone number and that I've contacted more than 5 times"

Constructing a Query - Query 4@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = ? AND " +

ContactsContract.Contacts.TIMES_CONTACTED + " > ? ";

mSelectionArgs = new String[]{ "1", "5" };

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Constructing a Query - Query 4@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = ? AND " +

ContactsContract.Contacts.TIMES_CONTACTED + " > ? ";

mSelectionArgs = new String[]{"1", "5"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

We modify our selection clause slightly, to also have the condition that the contact must have been contacted more than 5 times

Constructing a Query - Query 4@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = ? AND " +

ContactsContract.Contacts.TIMES_CONTACTED + " > ? ";

mSelectionArgs = new String[]{"1", "5"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Since we have a new condition, we also add the argument to the condition to our selection arguments String array

Constructing a Query - Query 4@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = ? AND " +

ContactsContract.Contacts.TIMES_CONTACTED + " > ? ";

mSelectionArgs = new String[]{"1", "5"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

SELECT _ID, DISPLAY_NAME, TIMES_CONTACTED FROM ContactsContract.Contacts WHERE HAS_PHONE_NUMBER = 1

AND TIMES_CONTACTED > 5

Constructing a Query - Query 4@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = ? AND " +

ContactsContract.Contacts.TIMES_CONTACTED + " > ? ";

mSelectionArgs = new String[]{"1", "5"};

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, null);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

The rest hasn't changed

Constructing a Query - Query 4

See the query4() method inside of ContactsContractQueryExample.tar

Constructing a Query - Query 5

Consider the following SQL query

SELECT _ID, DISPLAY_NAME

FROM ContactsContract.Contacts

WHERE HAS_PHONE_NUMBER = 1

ORDER BY DISPLAY_NAME

"Get the _ID and DISPLAY_NAME for all contacts that have phone numbers, and sort the results by DISPLAY_NAME"

Constructing a Query - Query 5

FYI, we will build this query off of query3, not query4

Constructing a Query - Query 5@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts. _ID,

ContactsContract.Contacts. DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts. HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{ "1" };

mOrderBy = ContactsContract.Contacts. DISPLAY_NAME;

mCursor = getContentResolver().query(

ContactsContract.Contacts. CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, mOrderBy);

mListColumns = new String[] {

ContactsContract.Contacts. DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter( this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Constructing a Query - Query 5@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mOrderBy = ContactsContract.Contacts.DISPLAY_NAME;

mCursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, mOrderBy);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

Here we have a String specifying the column by which we want to sort. In this case, the DISPLAY_NAME

Constructing a Query - Query 5@Override

public void onCreate(Bundle savedInstanceState) {

mProjection = new String[] { ContactsContract.Contacts._ID,

ContactsContract.Contacts.DISPLAY_NAME };

mSelectionClause = ContactsContract.Contacts.HAS_PHONE_NUMBER +

" = ? ";

mSelectionArgs = new String[]{"1"};

mOrderBy = ContactsContract.Contacts.DISPLAY_NAME;

mCursor = getContentResolver(). query(

ContactsContract.Contacts.CONTENT_URI, mProjection,

mSelectionClause, mSelectionArgs, mOrderBy);

mListColumns = new String[] {

ContactsContract.Contacts.DISPLAY_NAME };

mListItems = new int[] { R.id.contact_name };

mCursorAdapter = new SimpleCursorAdapter(this,

R.layout.query1, mCursor, mListColumns, mListItems);

}

SELECT _ID, DISPLAY_NAME FROM ContactsContract.Contacts WHERE HAS_PHONE_NUMBER = 1 ORDER BY DISPLAY_NAME

Constructing a Query - Query 5

See the query5() method inside of ContactsContractQueryExample.tar

Iterating through query results

You may not always want to add the results from a query to a ListView. Sometimes you just need to go through the results one-by-one

Iterating through query resultsCursor cursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI,

projection,

selectionClause,

selectionArgs,

null);

if (cursor != null) {

while (cursor.moveToNext()) {

cursor.getString(1);

}

}

Iterating through query resultsCursor cursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI,

projection,

selectionClause,

selectionArgs,

null);

if(cursor != null) {

while(cursor.moveToNext()) {

cursor.getString(1);

}

}

After executing the query ...

Iterating through query resultsCursor cursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI,

projection,

selectionClause,

selectionArgs,

null);

if(cursor != null) {

while(cursor.moveToNext()) {

cursor.getString(1);

}

}

Make sure that the Cursor is not null before using it

Iterating through query resultsCursor cursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI,

projection,

selectionClause,

selectionArgs,

null);

if(cursor != null) {

while(cursor.moveToNext()) {

cursor.getString(1);

}

}

This returns true as long as there are more results to be fetched

Iterating through query resultsCursor cursor = getContentResolver().query(

ContactsContract.Contacts.CONTENT_URI,

projection,

selectionClause,

selectionArgs,

null);

if(cursor != null) {

while(cursor.moveToNext()) {

cursor.getString(1);

}

}

Get the String represention of column number 1 (or use another integer if you want a different column value)

Iterating through query results

See ContentProviderExample.tar

Creating a Content Provider

There are two ways to store your data using a Content Provider

1. File data○ photos, audio, video, etc

2. Structured data○ data fit for a database

We will look at structured data using SQLite databases

Creating a Content Provider

Because writing to databases is a sensitive operation, in the next examples we will perform operations on our own SQLite database

Creating a Content Provider

The steps for creating an SQLite DB for your app is not what you're used to, because doing it right means that you also need to understand URIs

Creating a Content Provider

You should add the content provider via the Android Studio menu● Click File > New > Other > Content Provider● Provide a name for the Content Provider● Provide an Authorities URI

○ This should be your package name followed by “.provider”

● Click Finish

Creating a Content Provider

Decide on the name of your database now, and we will add it as a field to the ContentProvider

public class MyProvider extends ContentProvider {

public final static String DBNAME = "NameDatabase";

...

}

Creating a Content Provider

Next we need to add a String containing the SQL query for creating the necessary tables for our database

In our example, we will create a table in our database with the following structure

Column Name Type

_ID Integer PRIMARY KEY

FirstName TEXT

LastName TEXT

Creating a Content Providerpublic class MyProvider extends ContentProvider {

public final static String DBNAME = "NameDatabase";

private static final String SQL_CREATE_MAIN =

"CREATE TABLE Users ( " +

" _ID INTEGER PRIMARY KEY, " +

"FirstName TEXT, " +

"LastName TEXT )";

...

}

If you're unfamiliar with SQL, see this page

Creating a Content Provider

● We will also add the CONTENT_URI Uri as a convenient way to get the URI for our database.

● We make it final because we don't want it to be modified after it has been set

Creating a Content Providerpublic class MyProvider extends ContentProvider {

public final static String DBNAME = "NameDatabase";

private static final String SQL_CREATE_MAIN =

"CREATE TABLE Users ( " +

" _ID INTEGER PRIMARY KEY, " +

"FirstName TEXT, " +

"LastName TEXT )";

public static final Uri CONTENT_URI = Uri.parse("content://my.package.name.provider");

...

}

Creating a Content Provider

Before we implement any of the methods inside of your new ContentProvider, we need to add an inner class which extends SQLiteOpenHelper. This class will take care of

● Opening the database if it exists● Creating it if it does not

Creating a Content Providerpublic class MyProvider extends ContentProvider {

...

protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

MainDatabaseHelper(Context context) {

super(context, "NamesDatabase", null, 1);

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(SQL_CREATE_MAIN);

}

@Override

public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

}

}

}

Creating a Content Providerpublic class MyProvider extends ContentProvider {

...

protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

MainDatabaseHelper(Context context) {

super(context, "NamesDatabase", null, 1);

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(SQL_CREATE_MAIN);

}

@Override

public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

}

}

}

The String we created previously are here

Creating a Content Providerpublic class MyProvider extends ContentProvider {

...

protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

MainDatabaseHelper(Context context) {

super(context, "NamesDatabase", null, 1);

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(SQL_CREATE_MAIN);

}

@Override

public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

}

}

}

Make sure to call super, and pass the name of the database as the second argument

Creating a Content Providerpublic class MyProvider extends ContentProvider {

...

protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

MainDatabaseHelper(Context context) {

super(context, "NamesDatabase", null, 1);

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(SQL_CREATE_MAIN);

}

@Override

public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

}

}

}

The database will be created when onCreate() is called on our inner class. Note that this onCreate() doesn't get called until you try to access the database

Creating a Content Provider

Now we can implement the methods for our ContentProvider

Implementing the onCreate() method

public class MyContentProvider extends ContentProvider {

...

@Override

public boolean onCreate() {

mOpenHelper = new MainDatabaseHelper(getContext());

return true;

}

...

}

Implementing the onCreate() method

public class MyContentProvider extends ContentProvider {

...

@Override

public boolean onCreate() {

mOpenHelper = new MainDatabaseHelper(getContext());

return true;

}

...

}

We create an instance of our MainDatabaseHelper so that we can use it later for reading and modifying our NamesDatabase

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

We must return a Uri. We will return a Uri that has the new id of the item that will be inserted in this method

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

This Uri can be used to identify the table in our database, but since we only have one table, we don't need to use it in this function

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

These are the values that will be inserted. They are key-value pairs

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

We get the FirstName and LastName values that were passed in

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

Before you call insert() and update(), you should check for invalid values and return null if there is any invalid input. We don't use fname and lname afterward, as we are just trying to illustrate how to use ContentValues

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

We need to call getWritableDatabase() to create and/or open our database which will be used for reading and writing

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

We can insert() on our Users table, passing the values that need to be inserted

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

Because the _ID column is the primary key, we don't need to specify a value for it. It will automatically be added for us

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

That _ID value is returned from the call to insert(), we store it in this long int

Implementing the insert() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Uri insert(Uri uri, ContentValues values) {

String fname = values.getAsString("FirstName");

String lname = values.getAsString("LastName");

long id = mOpenHelper.getWritableDatabase()

.insert("Users", null, values);

return Uri.withAppendedPath(CONTENT_URI, "" + id);

}

...

}

Here we return the Uri that can be used to identify the row that was just inserted. For examplecontent://my.package.name.provider/Users/1

Implementing the update() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public int update(Uri uri, ContentValues values,

String selection, String[] selectionArgs) {

return mOpenHelper.getWritableDatabase().

update("Users", values, selection, selectionArgs);

}

...

}

Implementing the update() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public int update(Uri uri, ContentValues values,

String selection, String[] selectionArgs) {

return mOpenHelper.getWritableDatabase().

update("Users", values, selection, selectionArgs);

}

...

}

After checking for invalid values (not shown here), we simply use our mOpenHelper to update the Users table, and return that value. Next we implement the delete() method

Implementing the delete() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public int delete(Uri uri, String whereClause,

String[] whereArgs) {

return mOpenHelper.getWritableDatabase().

delete(TABLE_NAMESTABLE, whereClause, whereArgs);

}

...

}

Implementing the delete() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public int delete(Uri uri, String whereClause,

String[] whereArgs) {

return mOpenHelper.getWritableDatabase().

delete(TABLE_NAMESTABLE, whereClause, whereArgs);

}

...

}

Next, we implement the query() method

Implementing the delete() methodpublic class MyContentProvider extends ContentProvider {

...

@Override

public Cursor query(Uri table, String[] columns,

String selection, String[] args, String orderBy) {

return mOpenHelper.getReadableDatabase()

.query("Users", columns, selection, args, null, null, orderBy);

}

...

}

Content Provider Permissions

Now that you've set up your ContentProvider, you will want to have external apps require permission to read/write your data

More on your own permissions here

Content Provider Permissions

By default, anyone can read from or write to your ContentProvider

Take the steps necessary to protect you data

Content Provider Permissions

1. Open the AndroidManifest.xml file2. Add a <permission … /> tag above the

<application> tag3. Set the android:name attribute for your permission

○ my.package.name.provider.permission.READ_PERMISSION○ (Create a String resource for this permission String)

4. Save the file

You can add as many permission Strings you want, how you use them is more important

Content Provider Permissions● Single read-write provider-level permission

○ One permission that controls both read and write access to the entire provider, specified with the

■ android:permission attribute of the <provider> element.

● Separate read and write provider-level permission○ A read permission and a write permission for the entire provider

■ android:readPermission

■ android:writePermission

■ They take precedence over the permission required by android:permission.

Content Provider Permissions

See ContentProviderExternalUserExample.tar

Make sure that you've also installed ContentProviderExample.tar on the same device, so that the external user can use its content provider

Viewing ContentProvider data

● We want to create a class to view ContentProvider data when an application calls ACTION_VIEW

● Implement getType() in ContentProvider to return MimeType

● Can have multiple Activities○ One displays single entry○ One displays list of entries

ContentProvider MimeTypes

● vnd.android.cursor.dir ○ Describes multiple entries○ Ex. vnd.android.cursor.dir/edu.fsu.cs.mobile.provider/transactions

● Starts with vnd.android.cursor.item○ Describes one entry

○ Ex. vnd.android.cursor.item/edu.fsu.cs.mobile.provider/transactions

ContentProvider MimeTypes

● Add intent-filter to view Activity● Add VIEW action● Add supported MimeTypes<action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><data android:scheme="content" /><data android:mimeType="vnd.android.cursor.dir/package.provider/table" /><data android:mimeType="vnd.android.cursor.item/package.provider/table" />

References

● The Busy Coder's Guide to Android Development - Mark Murphy

● Android Developers● The Mobile Lab at Florida State University