Thursday 4 July 2013

Writing Content Provider

Android provides a cleaner & simplistic approach to handle the structured data through SQLite databases. But ever wondered, if your application wants data to be shared with other applications?? First thought that strikes the mind is sharing the database file by keeping it at a common location, may be on SD card. This approach indeed can work for you. :) But wait, why not to give a second thought on this? What if user just wipes out all data from his SD card? Or what if just removes the card from phone & forgot to put it back? These are some examples of what might go wrong with the application. In both the cases, not only the application for which you shared but also, your own app will certainly loose all data and/or crash. Quite embarrassing...

Here, comes the elegant way of sharing your app data with other apps reliably. Content Providers!
Content provider is a wrapper over the database which allows other applications to access data generated by our app. The wrapper consists of the methods written for database's read, update & delete operations on SQLite database.

For 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:

Here the name refers to the class MyContentProvider which extends ContentProvider class. You need to override 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;
        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.