2015-05-17

[Android] 範例: 使用SQLiteOpenHelper以及UriMatcher的ContentProvider. A simple example of ContentProvider which uses SQLiteOpenHelper and UriMatcher

This is a simple example of ContentProvider which uses SQLiteOpenHelper to create a database.


1.  Define a Database Contract.
It contains the following information about a Database.
(1) Authority
(2) Table names
(3) column names of each Table
(4) content Uri




import android.net.Uri;
import android.provider.BaseColumns;

import static com.example.viki_hung.imageforumviewer.Constant.PACKAGE_NAME;

/**
 * The contract holds database setting for forum content provider.
 */
public final class ForumDBContract {

    /**
     * the authority of Content Provider
     */
    static final String AUTHORITY = PACKAGE_NAME;

    /**
     * To prevent someone from accidentally instantiating the contract class,
     * give it an empty constructor.
     */
    private ForumDBContract() {
    }

    /**
     * Inner class that defines the Forum table contents
     */
    public static final class ForumEntry implements BaseColumns {

        public static final String FORUM_TABLE_NAME = "ForumList";
        public static final String FORUM_ID = "fid";
        public static final String FORUM_TITLE = "title";

    }

    /**
     * Inner class that defines the Topic table contents
     */
    public static final class TopicEntry implements BaseColumns {

        public static final String TOPIC_TABLE_NAME = "TopicList";
        public static final String TOPIC_ID = "tid";
        public static final String TOPIC_FORUM_ID = "fid";
        public static final String TOPIC_TITLE = "title";
        public static final String TOPIC_IMAGE = "image";
        public static final String TOPIC_IMAGE_LIST = "imagelist";

    }

    /**
     * Uri of Forum list content
     */
    static final Uri CONTENT_URI_FORUM_LIST =
            Uri.parse("content://" + AUTHORITY + "/" + ForumEntry.FORUM_TABLE_NAME);

    /**
     * Uri of Topic list content
     */
    static final Uri CONTENT_URI_TOPIC_LIST =
            Uri.parse("content://" + AUTHORITY + "/" + TopicEntry.TOPIC_TABLE_NAME);

}


2. Create a class extends SQLiteOpenHelper
It contains the following information.
(1) Database name
(2) Database version
(3) SQL command to create a database

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import static android.provider.BaseColumns._ID;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.ForumEntry.FORUM_ID;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.ForumEntry.FORUM_TABLE_NAME;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.ForumEntry.FORUM_TITLE;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.TopicEntry.TOPIC_FORUM_ID;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.TopicEntry.TOPIC_ID;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.TopicEntry.TOPIC_IMAGE;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.TopicEntry.TOPIC_IMAGE_LIST;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.TopicEntry.TOPIC_TABLE_NAME;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.TopicEntry.TOPIC_TITLE;

/**
 * Database create Helper of forum database
 */
class ForumDBHelper extends SQLiteOpenHelper {

    private static final String DEBUG_TAG = ForumDBHelper.class.getSimpleName();

    private static final String DATABASE_NAME = "ForumList";
    private static final int VERSION_INITIAL = 1;

    private static final String DATABASE_CREATE_FORUM_LIST =
            "CREATE TABLE if not exists " + FORUM_TABLE_NAME + " ("
                    + _ID + " integer PRIMARY KEY autoincrement,"
                    + FORUM_ID + " TEXT, "
                    + FORUM_TITLE + " TEXT );";

    private static final String DATABASE_CREATE_TOPIC_LIST =
            "CREATE TABLE if not exists " + TOPIC_TABLE_NAME + " ("
                    + _ID + " integer PRIMARY KEY autoincrement,"
                    + TOPIC_ID + " TEXT, "
                    + TOPIC_FORUM_ID + " TEXT, "
                    + TOPIC_TITLE + " TEXT, "
                    + TOPIC_IMAGE + " TEXT, "
                    + TOPIC_IMAGE_LIST + " TEXT );";

    ForumDBHelper(Context context) {
        super(context, DATABASE_NAME, null, VERSION_INITIAL);
    }

    @Override public void onCreate(SQLiteDatabase db) {
        Log.d(DEBUG_TAG, "DB onCreate");
        db.execSQL(DATABASE_CREATE_FORUM_LIST);
        db.execSQL(DATABASE_CREATE_TOPIC_LIST);
    }

    @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

}


3. Create a ContentProvider which uses SQLiteOpenHelper and UriMatcher

package com.example.viki_hung.imageforumviewer;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

import static com.example.viki_hung.imageforumviewer.ForumDBContract.AUTHORITY;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.CONTENT_URI_FORUM_LIST;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.CONTENT_URI_TOPIC_LIST;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.ForumEntry.FORUM_TABLE_NAME;
import static com.example.viki_hung.imageforumviewer.ForumDBContract.TopicEntry.TOPIC_TABLE_NAME;

/**
 * The Content Provider of the image forum
 */
public class ForumContentProvider extends ContentProvider {

    private static final String DEBUG_TAG = ForumContentProvider.class.getSimpleName();

    /**
     * UriMatcher to match URI to a code
     */
    private static final UriMatcher sUriMatcher;

    private static final int URI_MATCH_FORUM_LIST = 1;
    private static final int URI_MATCH_TOPIC_LIST = 2;

    /**
     * match URI to a code using UriMatcher
     */
    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(AUTHORITY, FORUM_TABLE_NAME, URI_MATCH_FORUM_LIST);
        sUriMatcher.addURI(AUTHORITY, TOPIC_TABLE_NAME, URI_MATCH_TOPIC_LIST);
    }

    private ForumDBHelper mDbHelper;

    @Override public boolean onCreate() {
        Log.d(DEBUG_TAG, "CP onCreate");
        mDbHelper = new ForumDBHelper(getContext());
        return true;
    }

    @Override public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)) {
        case URI_MATCH_FORUM_LIST: {
            return "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + FORUM_TABLE_NAME;
        }
        case URI_MATCH_TOPIC_LIST: {
            return "vnd.android.cursor.dir/vnd." + AUTHORITY + "." + TOPIC_TABLE_NAME;
        }
        default: {
            return null;
        }
        }
    }

    @Override public Uri insert(Uri uri, ContentValues values) {
        Uri returnUri = null;
        if (values == null || values.size() == 0) {
            return null;
        }

        try {
            SQLiteDatabase db = mDbHelper.getWritableDatabase();
            if (db == null) {
                return null;
            }
            long id;
            switch (sUriMatcher.match(uri)) {
            case URI_MATCH_FORUM_LIST: {
                // insert value to forum list
                id = db.insert(FORUM_TABLE_NAME, null, values);
                returnUri = Uri.withAppendedPath(CONTENT_URI_FORUM_LIST, String.valueOf(id));
                Log.d(DEBUG_TAG, "CP insert, uri=" + returnUri);
                break;
            }
            case URI_MATCH_TOPIC_LIST: {
                // insert value to topic list
                id = db.insert(TOPIC_TABLE_NAME, null, values);
                returnUri = Uri.withAppendedPath(CONTENT_URI_TOPIC_LIST, String.valueOf(id));
                Log.d(DEBUG_TAG, "CP insert, uri=" + returnUri);
                break;
            }
            default: {
                return null;
            }
            }

            getContext().getContentResolver().notifyChange(returnUri, null);
        } catch (Exception ignored) {
            Log.e(DEBUG_TAG, ignored.getMessage(), ignored);
        }
        return returnUri;
    }

    @Override public Cursor query(Uri uri, String[] projection, String selection,
                                  String[] selectionArgs, String sortOrder) {
        Cursor cursor = null;
        try {
            SQLiteDatabase db = mDbHelper.getReadableDatabase();
            if (db == null) {
                return null;
            }
            switch (sUriMatcher.match(uri)) {
            case URI_MATCH_FORUM_LIST: {
                Log.d(DEBUG_TAG, "CP query forum list.");
                cursor = db.query(FORUM_TABLE_NAME, projection, selection, selectionArgs,
                        null, null, sortOrder);
                break;
            }
            case URI_MATCH_TOPIC_LIST: {
                Log.d(DEBUG_TAG, "CP query topic list.");
                cursor = db.query(TOPIC_TABLE_NAME, projection, selection, selectionArgs,
                        null, null, sortOrder);
                break;
            }
            default: {
                return null;
            }
            }

            Log.d(DEBUG_TAG, "CP query result cursor_count=" + cursor.getCount());
        } catch (Exception ignored) {
            Log.e(DEBUG_TAG, ignored.getMessage(), ignored);
        }
        return cursor;
    }

    @Override public int delete(Uri uri, String selection, String[] selectionArgs) {
        int deleteCount = -1;
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        if (db == null) {
            return -1;
        }
        try {
            switch (sUriMatcher.match(uri)) {
            case URI_MATCH_FORUM_LIST: {
                Log.d(DEBUG_TAG, "CP delete forum list.");
                deleteCount = db.delete(FORUM_TABLE_NAME, selection, selectionArgs);
                break;
            }
            case URI_MATCH_TOPIC_LIST: {
                Log.d(DEBUG_TAG, "CP delete topic list.");
                deleteCount = db.delete(TOPIC_TABLE_NAME, selection, selectionArgs);
                break;
            }
            default: {
                return -1;
            }
            }
            getContext().getContentResolver().notifyChange(uri, null);
        } catch (Exception ignored) {
            Log.e(DEBUG_TAG, ignored.getMessage(), ignored);
        }
        return deleteCount;
    }

    @Override public int update(Uri uri, ContentValues values, String selection, String[]
            selectionArgs) {
        int updateCount = -1;
        try {
            SQLiteDatabase db = mDbHelper.getWritableDatabase();
            if (db == null) {
                return -1;
            }
            switch (sUriMatcher.match(uri)) {
            case URI_MATCH_FORUM_LIST: {
                Log.d(DEBUG_TAG, "CP update forum list.");
                updateCount = db.update(FORUM_TABLE_NAME, values, selection, selectionArgs);
                break;
            }
            case URI_MATCH_TOPIC_LIST: {
                Log.d(DEBUG_TAG, "CP update topic list.");
                updateCount = db.update(TOPIC_TABLE_NAME, values, selection, selectionArgs);
                break;
            }
            default: {
                return -1;
            }
            }
            getContext().getContentResolver().notifyChange(uri, null);
        } catch (Exception ignored) {
            Log.e(DEBUG_TAG, ignored.getMessage(), ignored);
        }
        return updateCount;
    }

}




4. Usage of the ContentProvider
Insert:
// new item
ContentValues values = new ContentValues();
values.put(FORUM_ID, forumId);
values.put(FORUM_TITLE, forumTitle);

// insert a record to DB
Uri uri = getContentResolver().insert(CONTENT_URI_FORUM_LIST, values);


delete:
// if parse json OK, clear topic list in DB
int dCount = getContentResolver().delete(
        CONTENT_URI_TOPIC_LIST,
        TOPIC_FORUM_ID + " = ?",
        new String[]{fid});