Best practices for exposing multiple tables using content providers in Android Best practices for exposing multiple tables using content providers in Android android android

Best practices for exposing multiple tables using content providers in Android


It's probably a bit late for you, but others may find this useful.

First you need to create multiple CONTENT_URIs

public static final Uri CONTENT_URI1 =     Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri1");public static final Uri CONTENT_URI2 =     Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri2");

Then you expand your URI Matcher

private static final UriMatcher uriMatcher;static {    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);    uriMatcher.addURI(PROVIDER_NAME, "sampleuri1", SAMPLE1);    uriMatcher.addURI(PROVIDER_NAME, "sampleuri1/#", SAMPLE1_ID);          uriMatcher.addURI(PROVIDER_NAME, "sampleuri2", SAMPLE2);    uriMatcher.addURI(PROVIDER_NAME, "sampleuri2/#", SAMPLE2_ID);      }

Then create your tables

private static final String DATABASE_NAME = "sample.db";private static final String DATABASE_TABLE1 = "sample1";private static final String DATABASE_TABLE2 = "sample2";private static final int DATABASE_VERSION = 1;private static final String DATABASE_CREATE1 =    "CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE1 +     " (" + _ID1 + " INTEGER PRIMARY KEY AUTOINCREMENT," +     "data text, stuff text);";private static final String DATABASE_CREATE2 =    "CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE2 +     " (" + _ID2 + " INTEGER PRIMARY KEY AUTOINCREMENT," +     "data text, stuff text);";

Don't forget to add the second DATABASE_CREATE to onCreate()

You are going to use a switch-case block to determine what table is used. This is my insert code

@Overridepublic Uri insert(Uri uri, ContentValues values) {    Uri _uri = null;    switch (uriMatcher.match(uri)){    case SAMPLE1:        long _ID1 = db.insert(DATABASE_TABLE1, "", values);        //---if added successfully---        if (_ID1 > 0) {            _uri = ContentUris.withAppendedId(CONTENT_URI1, _ID1);            getContext().getContentResolver().notifyChange(_uri, null);            }        break;    case SAMPLE2:        long _ID2 = db.insert(DATABASE_TABLE2, "", values);        //---if added successfully---        if (_ID2 > 0) {            _uri = ContentUris.withAppendedId(CONTENT_URI2, _ID2);            getContext().getContentResolver().notifyChange(_uri, null);            }        break;    default: throw new SQLException("Failed to insert row into " + uri);    }    return _uri;                }

You will need to devide up the delete, update, getType, etc. Wherever your provider calls for DATABASE_TABLE or CONTENT_URI you will add a case and have DATABASE_TABLE1 or CONTENT_URI1 in one and #2 in the next and so on for as many as you want.


I recommend checking out the source code for the Android 2.x ContactProvider. (Which can be found online). They handle cross table queries by providing specialized views that you then run queries against on the back end. On the front end they are accessible to the caller via various different URIs through a single content provider. You'll probably also want to provide a class or two for holding constants for your table field names and URI strings. These classes could be provided either as an API include or as a drop in class, and will make it much easier for the consuming application to use.

Its a bit complex, so you might also want to check out how the calendar as well to get an idea of what you do and do not need.

You should only need a single DB adapter and a single Content provider per database (not per table) to do most of the work, but you can use multiple adapters/providers if you really want to. It just makes things a bit more complicated.


One ContentProvider can serve multiple tables, but they should be somewhat related. It will make a difference if you intend to sync your providers. If you want seperate syncs for, let's say Contacts, Mail or Calendar, you will need different providers for each of them, even if they end up being in the same database or are synced with the same service, because Sync Adapters are tied directly to a particular provider.

As far as I can tell, you can only use a single SQLiteOpenHelper per database, though, since it stores its meta information in a table within the database. So if your ContentProviders access the same database, you'll have to share the Helper somewhow.