Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Writing a Content Provider

Published? true
FormatLanguage: WikiFormat

Problem:

Often the application generates data, which can be processed and analyzed by another application. What is the safest way to achieve this, without giving direct access to our application's database?

Solution:

Writing a custom Content Provider is the Android way to allow other applications to access data generated by our app.

Discussion:

Content providers allow other applications to access the data generated by our app. For a custom content provider, we need to have the app database built up and we will be providing the wrapper over it for other applications. To make other apps aware that a content provider is available, declare it in AndroidManifest.xml as:

<provider android:authorities="com.example.android.contentprovider"
			android:name="MyContentProvider" />

Here the name refers to the class MyContentProvider which extends ContentProvider class. You need to override the following methods in this class.

onCreate();
delete(Uri, String, String[]);
getType(Uri);
insert(Uri, ContentValues);
query(Uri, String[], String, String[], String);
update(Uri, ContentValues, String, String[]);

Usually these are wrapper functions for SQL queries on the sqlite database. You parse the input parameters and perform the queries on your database.

public class MyContentProvider extends ContentProvider {

	DatabaseHelper mDatabase; // See Database Chapter
        private static final int RECORDS = 1;
	public static final Uri CONTENT_URI = Uri
			.parse("content://com.example.android.contentprovider");

	public static final String AUTHORITY = "com.example.android.contentprovider";
	private static final UriMatcher matcher = new UriMatcher(
			UriMatcher.NO_MATCH);
	
	static {
		matcher.addURI(AUTHORITY, "records", RECORDS);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// the app specific code for deleting records from database goes here
		return 0;
	}

	@Override
	public String getType(Uri uri) {
		int matchType = matcher.match(uri);
		switch (matchType) {
		case RECORDS:
			return ContentResolver.CURSOR_DIR_BASE_TYPE + "/records";
		default:
			throw new IllegalArgumentException("Unknown or Invalid URI " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
                //your app specific insertion code goes here
                // it can be as simple as follows; inserting all values in database and returning the record id
		long id = mDatabase.getWritableDatabase().insert(Helper.TABLE_NAME,
				null, values);
		uri = Uri.withAppendedPath(uri, "/" + id);
		return uri;
	}

	@Override
	public boolean onCreate() {
                //initialize your database constructs
		return true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
                //build your query with SQLiteQueryBuilder
		SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
		qBuilder.setTables(Helper.TABLE_NAME);
		int uriType = matcher.match(uri);
		
                //query the database and get result in cursor
		Cursor resultCursor = qBuilder.query(mDatabase.getWritableDatabase(),
				projection, selection, selectionArgs, null, null, sortOrder,
				null);
		resultCursor.setNotificationUri(getContext().getContentResolver(), uri);
		return resultCursor;

	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// to be implemented
		return 0;
	}

}

By providing a Content Provider you avoid giving access to your database to other developers and also reduce the chances of database inconsistency.

Download:

The source code for this project is in the Android Cookbook repository, http://github.com/IanDarwin/Android-Cookbook-Examples/,in the subdirectory ContentProviderSample.