Implement Content Provider in Android

Hey everyone!

As developers, we often need to create applications that can share data with other applications residing on the Android device. A content provider is similar to a database where one can query it, edit its content, as well as add or delete content using insert, update, delete, and query methods.

As mentioned on the developer's page, Content providers manage access to a structured set of data. They encapsulate the data, and provide mechanisms for defining data security. In this tutorial, we will learn how to implement a Content provider in Android.

Pre-requisites: Eclipse IDE, Android SDK

Step 1: Create Android project

Launch Eclipse IDE and create a new Android application project called AndroidContentProviderExample with package name com.app.myprovider and choose the target SDK as Android 4.4

Step 2: Create ContentProvider class

Let's write our own ContentProvider that will enable users to add a particular name in the Student table of the College database. Create a new class called MyProvider and write the following code!

MyProvider.java

package com.app.myprovider;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class MyProvider extends ContentProvider {

	public static final String PROVIDER_NAME = "com.app.provider.Names";
	public static final String URL = "content://" + PROVIDER_NAME + "/names";
	public static final Uri CONTENT_URI = Uri.parse(URL);
	public static final String NAME = "name";
	public static final String ID = "id";
	private static HashMap<String, String> namesMap;

	//database variables
	DBHelper dbHelper;
	private SQLiteDatabase database;
	static final String DATABASE_NAME = "College";
	static final String TABLE_NAME = "Student";
	static final int DATABASE_VERSION = 1;
	static final String CREATE_TABLE = 
			" CREATE TABLE " + TABLE_NAME +
			" (id INTEGER PRIMARY KEY AUTOINCREMENT, " + 
			" name TEXT NOT NULL);";

	// integer values used in content URI
	static final int NAMES = 1;
	static final int NAMES_ID = 2;
	static final UriMatcher uriMatcher;
	static{
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uriMatcher.addURI(PROVIDER_NAME, "names", NAMES);
		uriMatcher.addURI(PROVIDER_NAME, "names/#", NAMES_ID);
	}

	@Override
	public boolean onCreate() {
		// TODO Auto-generated method stub
		Context context = getContext();
		dbHelper = new DBHelper(context);
		// permissions to be writable
		database = dbHelper.getWritableDatabase();

		if(database == null)
			return false;
		else
			return true;	
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// TODO Auto-generated method stub
		SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
		queryBuilder.setTables(TABLE_NAME);

		switch (uriMatcher.match(uri)) {
		// maps all database column names
		case NAMES:
			queryBuilder.setProjectionMap(namesMap);
			break;
		case NAMES_ID:
			queryBuilder.appendWhere( ID + "=" + uri.getLastPathSegment());
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		if (sortOrder == null || sortOrder == ""){
			sortOrder = NAME;
		}
		Cursor cursor = queryBuilder.query(database, projection, selection, 
				selectionArgs, null, null, sortOrder);
		cursor.setNotificationUri(getContext().getContentResolver(), uri);

		return cursor;
	}

	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// TODO Auto-generated method stub
		long row = database.insert(TABLE_NAME, "", values);
		// If record is added successfully
		if(row > 0) {
			Uri newUri = ContentUris.withAppendedId(CONTENT_URI, row);
			getContext().getContentResolver().notifyChange(newUri, null);
			return newUri;
		}
		throw new SQLException("Fail to add a new record into " + uri);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// TODO Auto-generated method stub
		int count = 0;

		switch (uriMatcher.match(uri)){
		case NAMES:
			// delete all the records of the table
			count = database.delete(TABLE_NAME, selection, selectionArgs);
			break;
		case NAMES_ID:
			//gets the id
			String id = uri.getLastPathSegment();		
			count = database.delete( TABLE_NAME, ID +  " = " + id + 
					(!TextUtils.isEmpty(selection) ? " AND (" + 
							selection + ')' : ""), selectionArgs);
			break;
		default: 
			throw new IllegalArgumentException("Unsupported URI " + uri);
		}

		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// TODO Auto-generated method stub
		return 0;
	}


	private static class DBHelper extends SQLiteOpenHelper {

		public DBHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
			// TODO Auto-generated constructor stub
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			// TODO Auto-generated method stub
			db.execSQL(CREATE_TABLE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			// TODO Auto-generated method stub
			Log.w(DBHelper.class.getName(),
					"Upgrading database");
			db.execSQL("DROP TABLE IF EXISTS " +  TABLE_NAME);
			onCreate(db);
		}

	}


}

Step 3: Create Activity class

Next, let's create our Activity class called MainActivity that will allow user to add, delete or show the respective values.

MainActivity.java

package com.app.myprovider;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

    //delete all the records and the table of the database provider
	public void deleteAllNames(View view) {
		String URL = "content://com.app.provider.Names/names";
		Uri friends = Uri.parse(URL);
		int count = getContentResolver().delete(
				friends, null, null);
		String countNum = "App: "+ count +" records are deleted.";
		Toast.makeText(getBaseContext(), 
				countNum, Toast.LENGTH_LONG).show();

	}

    //add a new name
	public void addName(View view) {
		ContentValues values = new ContentValues();

		values.put(MyProvider.NAME, 
				((EditText)findViewById(R.id.name)).getText().toString());

		Uri uri = getContentResolver().insert(
				MyProvider.CONTENT_URI, values);

		Toast.makeText(getBaseContext(), 
				"App:" + uri.toString() + " inserted!", Toast.LENGTH_LONG).show();
	}

    //display all names
	public void showAllNames(View view) {
		String URL = "content://com.app.provider.Names/names";
		Uri friends = Uri.parse(URL);
		Cursor c = getContentResolver().query(friends, null, null, null, "name");
		String result = "App Results:";

		if (!c.moveToFirst()) {
			Toast.makeText(this, result+" no content yet!", Toast.LENGTH_LONG).show();
		}else{
			do{
				result = result + "\n" + c.getString(c.getColumnIndex(MyProvider.NAME)); 
			} while (c.moveToNext());
			Toast.makeText(this, result, Toast.LENGTH_LONG).show();
		}

	}

}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >
    <EditText
        android:id="@+id/name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/name" />

    <Button
        android:id="@+id/btnAdd"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/name"
        android:layout_marginTop="30dp"
        android:onClick="addName"
        android:text="@string/add" />

    <Button
        android:id="@+id/btnShow"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/btnAdd"
        android:layout_below="@+id/btnAdd"
        android:layout_marginTop="20dp"
        android:onClick="showAllNames"
        android:text="@string/show" />

    <Button
        android:id="@+id/btnDelete"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/btnShow"
        android:layout_below="@+id/btnShow"
        android:layout_marginTop="20dp"
        android:onClick="deleteAllNames"
        android:text="@string/delete" />

</RelativeLayout>

strings.xml

    <string name="name">Name</string>
    <string name="add">Add a new name</string>
    <string name="show">Show all names</string>
    <string name="delete">Delete all names</string>

Step 4: Register Provider in Manifest file

Further, for Android to use our provider it is important to register the same in the AndroidManifest.xml as follows!

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.myprovider"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
            android:name=".MyProvider"
            android:authorities="com.app.provider.Names" >
        </provider>

    </application>
</manifest>

Finally, make sure no errors are present. Run the application on an Android device and you should be able to insert, delete and display the list of names as follows! 😄

android_content_provider_output_1

android_content_provider_output_2

android_content_provider_output_3

android_content_provider_output_4

Reference: Android Content Providers