Android App Development: Android Content Providers

By
On April 20, 2011

In the last post we created a sqlite database android application. We saw that the database file is stored in the file system directories of that application meaning that the database cannot be accessed from another application. You can apply the same thing on any resources within your application (Files, images, videos, …).

But there is a method to expose your data across multiple applications: Content Providers.
Content Providers expose an application’s data across all other applications, you can use content providers to store or retrieve data of one application from any other application.

Android default content providers:

There are many built-in content providers supplied by OS. They are defined in the android.provider package, they include:

  • Browser.
  • Calllog.
  • Live Folders.
  • Contacts Contract.
  • Media Store.
  • Settings.

content providers basics:

The concept of content providers is pretty similar to the concept of ASP.NET Web Services they provide data encapsulation through exposing data by URis. Any content provider is invoked by a URi in the form of content://provider_name . for example the URi of the Contacts content provider that retrieves all contacts is in the following form content://contacts/people. If you want to retrieve a particular contact (by its ID) then it would be in this form: content://contacts/people/5.

You do not need to write the URis of the content providers manually as they are stored as constant values in their respective content provider classes.

The Uri of the Contacts phones content provider is defined in:

ContactsContract.CommonDataKinds.Phone.CONTENT_URI

(content://com.android.contacts/data/phones)

The Uri of the browser Bookmarks content provider is defined in

Browser.BOOKMARKS_URI

(content://browser/bookmarks)

The Media store (Video) stored in external device (SD Card) is defined in

MediaStore.Video.Media.EXTERNAL_CONTENT_URI

(content://media/external/video/media) and so on.

Content providers allow you to perform basic CRUD operations: Create,Read, Update and Delete on data.

Making Queries:

To retrieve data from a content provider we run a sql-like query using ManagedQuery object. The ManagedQuery object returns a cursor holding the result set.

To retrieve a list of all contacts and display them in a ListView
We first define our activity xml layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:id="@+id/txt"
  />
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/list"
/>
</LinearLayout>

And define the layout of each row in the ListView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="https://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  >
  <TextView
  android:layout_width="100px"
  android:layout_height="wrap_content"
  android:id="@+id/txtName"
  android:layout_weight="1"
  />
  <TextView
  android:layout_width="100px"
  android:layout_height="wrap_content"
  android:id="@+id/txtNumber"
  android:layout_weight="1"
  />
</LinearLayout>

Remember to add the following permission to the manifest.xml file

<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

To retrieve the contacts and bind them to the listView:

String [] projection=new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone._ID};
        txt.setText(ContactsContract.PhoneLookup.CONTENT_FILTER_URI.toString());
       Uri contacts =  ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

        Cursor managedCursor = managedQuery(contacts,projection,null,null,null);
        //Cursor managedCursor =cr.query(contacts, projection, null, null, null);
        ListAdapter sca=new SimpleCursorAdapter(this,R.layout.listrow,managedCursor,projection,to);
        list.setAdapter(sca);

The above code retrieves all the contacts in the following steps:

  1. We first define the projection of our query, we define the columns we want to retrieve in the result set.We define a String array containing the names of the columns we want to retreieve.The contacts column names are defined in ContactsContract.CommonDataKinds.Phone class.Note that we need to retrieve the _ID column as the cursor that retrieves the data expects such a column to be there.
  2. We specify the Uri of the content provider ContactsContract.CommonDataKinds.Phone.CONTENT_URI
  3. We retrieve the data by a cursor
    Cursor managedCursor = managedQuery(contacts,projection,null,null,null);The cursor is retrieved by executing a managedQuery which has the following parameters: 

    1. The Uri of the content provider.
    2. A String Array of the columns to be retrieved (projection)
    3. Where clause.
    4. String array containing selection arguments values.
    5. String representing the order by clause, we can use it but here it will be null. If we want to sort the contacts by name it would be ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME +“ asc”
  4. Then we create a list adapeter using the cursor and bind the ListView to it.

The previous example retrieves all the contacts but what if we want to retrieve a certain contact by name:
There are two ways:

  1. Using the same code above but adding a where clause and selection arguments to the managed wuery so it becomes like this:
    Cursor managedCursor = managedQuery(contacts,projection,ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+"=?"
  2. ,new String[]{"Jack"},null);

    This retrieves contact info of a person named Jack.

  3. The other method is to inject the query in the Uri, instead of using Uri
    contacts =  ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

    we use:

    Uri contacts=Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI,
  4. Uri.encode("Jack"));

    This is equivalent to the following Uri content://com.android.contacts/data/phones/Jack.

Inserting,updating and deleting:

To insert data using a content provider there are two methods

First:
Using the Insert() method of your activity’s content resolver object. Like this example t insert a new bookmark to the browser:

ContentValues cv=new ContentValues();
      cv.put(Browser.BookmarkColumns.TITLE, "End Gadget");
      cv.put(Browser.BookmarkColumns.URL, "https://www.engadget.com/");
      cv.put(Browser.BookmarkColumns.BOOKMARK,1);
      Uri u= getContentResolver().insert(Browser.BOOKMARKS_URI, cv);

We create a ContentValues object and add to it all the required fields, then we call getContentResolver().insert method which returns the Uri of the newly inserted item.
It would be in this example content://browser/bookmarks/17
We can use the generated Uri to update or delete the item later.

Second:
We can replace the getcontentresolver().insert() method with bulkInsert method if we want to insert multiple items at a time.
The bulkInsert(Uri url,ContentValues[] values) method returns the number of new items created.

Updating info using Content Providers:

To update data using content providers, we use getContnetResolver.Update() method:
This code updates the title of an existing browser bookmark:

ContentValues cv=new ContentValues();
cv.put(Browser.BookmarkColumns.TITLE, "End Gadget mod");
      //uriBook= getContentResolver().insert(Browser.BOOKMARKS_URI, cv);
      getContentResolver().update(Browser.BOOKMARKS_URI, cv, BookmarkColumns.TITLE+"=?", new String[]{"End Gadget"});

the Update method has the following parameters:

  • Content Providers Uri
  • ContentValues object having the new values
  • Where clause
  • String array of the where clause arguments values

Deleting info using Content Providers:

To delete info we use getContentResolver.Delete() method
To delete a bookmark:

getContentResolver().delete(Browser.BOOKMARKS_URI,BookmarkColumns.TITLE+"=?", new String[]{"Mobile Orchard"});

The delete function has the following parameters:

  • Content Providers Uri
  • Where clause
  • String array of the where clause arguments values

Remember to add the following permissions to the manifest.xml to add and read browser bookmarks:

<uses-permission android:name="android.permission.WRITE_CONTACTS"></uses-permission>
<uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"></uses-permission>

That is it for todays tutorial, check back next week for my next Android App Development Tutorial.