Top Banner
Mobile Programming Lecture 10 ContentProviders
125

Mobile Programming Lecture 10

Feb 24, 2016

Download

Documents

Ferreira santos

Mobile Programming Lecture 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? - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Mobile Programming Lecture 10

Mobile ProgrammingLecture 10

ContentProviders

Page 2: Mobile Programming Lecture 10

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?

• When should you disable a Sensor?

Page 3: Mobile Programming Lecture 10

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?

Page 4: Mobile Programming Lecture 10

Agenda

• ContentProviders

• Querying existing databases

• Creating a database for your app

• Manipulating data: insert, update, and delete

• Content provider permissions

Page 5: Mobile Programming Lecture 10

Android Application Components

1. Activity

2. Broadcast Receiver

3. Content Provider

4. Service

Page 6: Mobile Programming Lecture 10

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

Page 7: Mobile Programming Lecture 10

Content Provider Basics

• When you want to access data in a content provider, you must 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.

Page 8: Mobile Programming Lecture 10

Content Provider Basics

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

• The reason you use a ContentProvider is o data is too complex for SharedPreferenceso expose your data to other applications

Page 9: Mobile Programming Lecture 10

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

Page 10: Mobile Programming Lecture 10

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

Page 11: Mobile Programming Lecture 10

Requesting Permission

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

android.permission.READ_CONTACTS

Page 12: Mobile Programming Lecture 10

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

Page 13: Mobile Programming Lecture 10

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);

}

}

Page 14: Mobile Programming Lecture 10

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

Page 15: Mobile Programming Lecture 10

Constructing a Query

Consider the following SQL queries

Page 16: Mobile Programming Lecture 10

Constructing a Query - Query 1

SELECT * FROM ContactsContract.Contacts

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

Page 17: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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); }

Page 18: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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()

Page 19: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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.

Page 20: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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.

Page 21: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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 *

Page 22: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 23: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 24: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 25: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 26: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 27: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 28: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 29: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 30: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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 now. But since we want to attach our results to a ListView, we need to add a few more lines of code

Page 31: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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.

Page 32: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 33: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 34: Mobile Programming Lecture 10

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 as has following TextView

Page 35: Mobile Programming Lecture 10

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" />

Page 36: Mobile Programming Lecture 10

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

Page 37: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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); }

Page 38: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 39: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 40: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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"

Page 41: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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)

Page 42: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 43: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 44: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 45: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 46: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 47: Mobile Programming Lecture 10

Constructing a Query - Query 1@Overridepublic 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

Page 48: Mobile Programming Lecture 10

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

Page 49: Mobile Programming Lecture 10

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"

Page 50: Mobile Programming Lecture 10

Constructing a Query - Query 2@Overridepublic 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);}

Page 51: Mobile Programming Lecture 10

Constructing a Query - Query 2@Overridepublic 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.

Page 52: Mobile Programming Lecture 10

Constructing a Query - Query 2@Overridepublic 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

Page 53: Mobile Programming Lecture 10

Constructing a Query - Query 2@Overridepublic 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

Page 54: Mobile Programming Lecture 10

Constructing a Query - Query 2@Overridepublic 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

Page 55: Mobile Programming Lecture 10

Constructing a Query - Query 2

See the query2() method inside of ContactsContractQueryExample.tar

Page 56: Mobile Programming Lecture 10

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"

Page 57: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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);}

Page 58: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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);}

mProjection has not changed

Page 59: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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 String

Page 60: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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 "?"

Page 61: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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

Page 62: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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

Page 63: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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

Page 64: Mobile Programming Lecture 10

Constructing a Query - Query 3@Overridepublic 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()

Page 65: Mobile Programming Lecture 10

Constructing a Query - Query 3

See the query3() method inside of ContactsContractQueryExample.tar

Page 66: Mobile Programming Lecture 10

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"

Page 67: Mobile Programming Lecture 10

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,

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);

}

Page 68: Mobile Programming Lecture 10

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,

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);

}

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

Page 69: Mobile Programming Lecture 10

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,

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);

}

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

Page 70: Mobile Programming Lecture 10

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,

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_NAME, TIMES_CONTACTED FROM ContactsContract.Contacts WHERE HAS_PHONE_NUMBER = 1

AND TIMES_CONTACTED > 5

Page 71: Mobile Programming Lecture 10

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);}

This rest hasn't changed

Page 72: Mobile Programming Lecture 10

Constructing a Query - Query 4

See the query4() method inside of ContactsContractQueryExample.tar

Page 73: Mobile Programming Lecture 10

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"

Page 74: Mobile Programming Lecture 10

Constructing a Query - Query 5

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

Page 75: Mobile Programming Lecture 10

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,

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);

}

Page 76: Mobile Programming Lecture 10

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,

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 have a String specifying the column by which we want to sort. In this case, the DISPLAY_NAME

Page 77: Mobile Programming Lecture 10

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,

null, null, 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

Page 78: Mobile Programming Lecture 10

Constructing a Query - Query 5

See the query5() method inside of ContactsContractQueryExample.tar

Page 79: Mobile Programming Lecture 10

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

Page 80: Mobile Programming Lecture 10

Iterating through query resultsCursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, selectionClause, null, null);

if(cursor != null) {while(cursor.moveToNext()) {

cusor.getString(1);}

}

Page 81: Mobile Programming Lecture 10

Iterating through query resultsCursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, selectionClause, null, null);

if(cursor != null) {while(cursor.moveToNext()) {

cusor.getString(1);}

}

After executing the query ...

Page 82: Mobile Programming Lecture 10

Iterating through query resultsCursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, selectionClause, null, null);

if(cursor != null) {while(cursor.moveToNext()) {

cusor.getString(1);}

}

Make sure that the Cursor is not null before using it

Page 83: Mobile Programming Lecture 10

Iterating through query resultsCursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, selectionClause, null, null);

if(cursor != null) {while(cursor.moveToNext()) {

cusor.getString(1);}

}

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

Page 84: Mobile Programming Lecture 10

Iterating through query resultsCursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, selectionClause, null, null);

if(cursor != null) {while(cursor.moveToNext()) {

cusor.getString(1);}

}

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

Page 85: Mobile Programming Lecture 10

Iterating through query results

See ContentProviderExample.tar

Page 86: Mobile Programming Lecture 10

Creating a Content Provider

There are two ways to store your data using a content provider

1. File data: photos, audio, video, etc2. Structured data

o data fit for a database

We will look at structured data using SQLite databases

Page 87: Mobile Programming Lecture 10

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

Page 88: Mobile Programming Lecture 10

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

Page 89: Mobile Programming Lecture 10

Creating a Content Provider

You should add the content provider via the Manifest file

• Open the Manifest file and click on the Application Tab

• Under Application Nodes, click Add ...

• Select Provider

• Under Attributes for Provider, click on the Name* link

• Enter the name for your Provider and press Enter

• Mouseover the class name in the new fileo Select add unimplemented methods

• Go back to the Manifest file

• Under Attributes for Provider, go to the Authorities* field and click Browse

• Click on New String...

• Enter a resource name for your string in the R.string field, e.g. "authority"

• Enter your package name in the String field, followed by ".provider“, done!

Page 90: Mobile Programming Lecture 10

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";

...}

Page 91: Mobile Programming Lecture 10

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

Page 92: Mobile Programming Lecture 10

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

Page 93: Mobile Programming Lecture 10

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

Page 94: Mobile Programming Lecture 10

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");

...}

Page 95: Mobile Programming Lecture 10

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

Page 96: Mobile Programming Lecture 10

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) {

}

}

}

Page 97: Mobile Programming Lecture 10

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

Page 98: Mobile Programming Lecture 10

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

Page 99: Mobile Programming Lecture 10

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

Page 100: Mobile Programming Lecture 10

Creating a Content Provider

Now we can implement the methods for our ContentProvider

Page 101: Mobile Programming Lecture 10

Implementing the onCreate() method

public class MyContentProvider extends ContentProvider {...@Overridepublic boolean onCreate() {

mOpenHelper = new MainDatabaseHelper(getContext());

return true;}

...}

Page 102: Mobile Programming Lecture 10

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

Page 103: Mobile Programming Lecture 10

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); }

...}

Page 104: Mobile Programming Lecture 10

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

Page 105: Mobile Programming Lecture 10

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

Page 106: Mobile Programming Lecture 10

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

Page 107: Mobile Programming Lecture 10

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

Page 108: Mobile Programming Lecture 10

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

Page 109: Mobile Programming Lecture 10

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

Page 110: Mobile Programming Lecture 10

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

Page 111: Mobile Programming Lecture 10

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

Page 112: Mobile Programming Lecture 10

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

Page 113: Mobile Programming Lecture 10

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

Page 114: Mobile Programming Lecture 10

Implementing the update() methodpublic class MyContentProvider extends ContentProvider {

...@Overridepublic int update(Uri uri, ContentValues values,

String selection, String[] selectionArgs) {

return mOpenHelper.getWritableDatabase().update("Users", values, selection, selectionArgs);

}

...}

Page 115: Mobile Programming Lecture 10

Implementing the update() methodpublic class MyContentProvider extends ContentProvider {

...@Overridepublic 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

Page 116: Mobile Programming Lecture 10

Implementing the delete() methodpublic class MyContentProvider extends ContentProvider {

...@Overridepublic int delete(Uri uri, String whereClause, String[] whereArgs) {

return mOpenHelper.getWritableDatabase().delete(TABLE_NAMESTABLE, whereClause, whereArgs);

}

...}

Page 117: Mobile Programming Lecture 10

Implementing the delete() methodpublic class MyContentProvider extends ContentProvider {

...@Overridepublic int delete(Uri uri, String whereClause, String[] whereArgs) {

return mOpenHelper.getWritableDatabase().delete(TABLE_NAMESTABLE, whereClause, whereArgs);

}

...}

Next, we implement the query() method

Page 118: Mobile Programming Lecture 10

Implementing the delete() methodpublic class MyContentProvider extends ContentProvider {

...@Overridepublic Cursor query(Uri table, String[] columns, String selection,

String[] args, String orderBy) {

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

}...

}

Page 119: Mobile Programming Lecture 10

Implementing the delete() methodpublic class MyContentProvider extends ContentProvider {

...@Overridepublic Cursor query(Uri table, String[] columns, String selection,

String[] args, String orderBy) {

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

}...

}

Page 120: Mobile Programming Lecture 10

Content Provider Permissions

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

More on your own permissions here

Page 121: Mobile Programming Lecture 10

Content Provider Permissions

By default, anyone can read from or write to your content provider

Take the steps necessary to protect you data

Page 122: Mobile Programming Lecture 10

Content Provider Permissions

1. Open the Manifest file2. Click on the Permissions tab3. Click Add ... Permission4. In the Name field, enter

o my.package.name.provider.permission.READ_PERMISSIONo (Create a String resource for this permission String)

5. Done

You can add many permission Strings

Page 123: Mobile Programming Lecture 10

Content Provider Permissions

• Single read-write provider-level permissiono 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 permissiono 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.

Page 124: Mobile Programming Lecture 10

Content Provider Permissions

See ContentProviderExternalUserExample.tar

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

Page 125: Mobile Programming Lecture 10

References

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

• Android Developers

• The Mobile Lab at Florida State University