I'm trying to implement a ContentProvider wrapped around an SQLite database.
I've followed the tutorial here in building my ContentProvider: tutorial
I want to test what I have; so I'm attempting to instantiate my new ContentProvider, retrieve a Cursor from the query handler, and attach it to my CursorAdapter. Currently, I'm doing this in the onCreate of my Activity (I know this is bad practice, I'm just testing, I will move it to a service eventually).
Uri uri = Uri.parse("content://com.test.db.providers.Messages/messages");
String s[] = {"_id", "delivery_id", "user_id", "created_on", "subject", "summary", "messagetext", "read", "status"};
MessagesProvider p = new MessagesProvider();
if (p.open()) {
Cursor messages = p.query(uri, s, null, null, null);
startManagingCursor(messages);
}
When I launch my application, the onCreate method of my extended ContentProvider gets executed. The database helper object gets created, the database gets created, and the onCreate method returns true. However, when I try to use my ContentProvider (with the code above), in the open() method the database helper object gets created, but getWritableDatabase() returns null. Also, when I call open(), the reference to getContext() is null.
Note: everything else seems to be working fine. When I call query, it hits my query handler, recognizes the Uri and attempts to run my query code (which obviously blows up because the database object is null).
Here are my extended ContentProvider and database helper:
package com.test.db.providers;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import com.test.db.DbDefinitions;
import com.test.db.DbHelper;
public class MessagesProvider extends ContentProvider {
private DbHelper mDbHelper;
private SQLiteDatabase mDb;
private static final UriMatcher sUriMatcher;
private static final String PROVIDER_NAME = "com.test.db.providers.Messages";
private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/messages");
public static final String id = "_id";
public static final String delivery_id = "delivery_id";
public static final String user_id = "user_id";
public static final String created_on = "created_on";
public static final String subject = "subject";
public static final String summary = "summary";
public static final String messagetext = "messagetext";
public static final String status = "status";
private static final int MESSAGES = 1;
private static final int MESSAGES_ID = 2;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(PROVIDER_NAME, "messages", MESSAGES);
sUriMatcher.addURI(PROVIDER_NAME, "messages/#", MESSAGES_ID);
}
public boolean open() {
mDbHelper = new DbHelper(getContext());
mDb = mDbHelper.getWritableDatabase();
return (mDb == null) ? false : true;
}
public void close() {
mDbHelper.close();
}
@Override
public boolean onCreate () {
mDbHelper = new DbHelper(getContext());
mDb = mDbHelper.getWritableDatabase();
return (mDb == null) ? false : true;
}
@Override
public String getType (Uri uri) {
switch (sUriMatcher.match(uri)) {
case MESSAGES:
return "vnd.android.cursor.dir/com.test.messages";
case MESSAGES_ID:
return "vnd.android.cursor.item/com.test.messages";
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
switch (sUriMatcher.match(uri)) {
case MESSAGES:
return queryMessages(uri, projection, selection, selectionArgs, sortOrder);
default:
throw new IllegalArgumentException("Unknown Uri " + uri);
}
}
@Override
public Uri insert (Uri uri, ContentValues initialValues) {
switch (sUriMatcher.match(uri)) {
case MESSAGES:
return insertMessages(uri, initialValues);
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) {
switch (sUriMatcher.match(uri)) {
case MESSAGES:
return updateMessages(uri, values, selection, selectionArgs);
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
@Override
public int delete (Uri uri, String selection, String[] selectionArgs) {
switch (sUriMatcher.match(uri)) {
case MESSAGES:
return deleteMessages(uri, selection, selectionArgs);
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
/*
* Messages
*/
private Cursor queryMessages(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor c = mDb.query(DbDefinitions.TABLE_MESSAGES, projection, selection, selectionArgs, null, null, sortOrder);
if (c != null) {
c.moveToFirst();
}
return c;
}
private Uri insertMessages(Uri uri, ContentValues initialValues) {
ContentValues values;
if (initialValues != null)
values = new ContentValues(initialValues);
else
values = new ContentValues();
long rowId = mDb.insert(DbDefinitions.TABLE_MESSAGES, summary, values);
if (rowId > 0) {
Uri messageUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(messageUri, null);
return messageUri;
}
throw new SQLException("Failed to insert new message " + uri);
}
private int updateMessages(Uri uri, ContentValues values, String where, String[] whereArgs) {
int result = mDb.update(DbDefinitions.TABLE_MESSAGES, values, where, whereArgs);
getContext().getContentResolver().notifyChange(uri, null);
return result;
}
public int deleteMessages(Uri uri, String where, String[] whereArgs) {
// TODO flag message as deleted
return 0;
}
}
package com.test.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, DbDefinitions.DATABASE_NAME, null, DbDefinitions.DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DbDefinitions.DB_CREATE);
db.execSQL(DbDefinitions.DB_TEST_DATA);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO run upgrade string
db.execSQL("DROP TABLE IF EXISTS " + DbDefinitions.TABLE_MESSAGES);
onCreate(db);
}
}
I'm wondering if I should somehow be referencing whatever instance of MessagesProvider was created when I launched the application, instead of declaring a new one (p) and using it?
I updated the onCreate code in my Activity to the following, but managedQuery returned null:
Uri uri = Uri.parse("content://com.buyercompass.app.provider.Messages/messages");
String s[] = {"_id", "delivery_id", "user_id", "created_on", "subject", "summary", "messagetext", "read", "status"};
Cursor messages = managedQuery(uri, s, null, null, null);
if (messages != null)
startManagingCursor(messages);
ExampleCursorAdapter msg =
new ExampleCursorAdapter(this, messages);
setListAdapter(msg);