How can I split a long, single SQLiteOpenHelper into several classes, one for each table
Asked Answered
C

2

2

I know this has been asked a couple of times before, but in all those questions neither the OP's nor the people who answered, provided clear examples.

So what I'm trying to ask here is if having a class like this

public class MyDatabaseDB {

    // database constants
    public static final String DB_NAME = "mydatabase.db";
    public static final int    DB_VERSION = 1;

    // list table constants
    public static final String LIST_TABLE = "list";

    public static final String LIST_ID = "_id";
    public static final int    LIST_ID_COL = 0;

    public static final String LIST_NAME = "list_name";
    public static final int    LIST_NAME_COL = 1;

    // task table constants
    public static final String TASK_TABLE = "task";

    public static final String TASK_ID = "_id";
    public static final int    TASK_ID_COL = 0;

    public static final String TASK_LIST_ID = "list_id";
    public static final int    TASK_LIST_ID_COL = 1;

    public static final String TASK_NAME = "task_name";
    public static final int    TASK_NAME_COL = 2; 

    // CREATE and DROP TABLE statements
    public static final String CREATE_LIST_TABLE = 
            "CREATE TABLE " + LIST_TABLE + " (" + 
            LIST_ID   + " INTEGER PRIMARY KEY AUTOINCREMENT, " + 
            LIST_NAME + " TEXT    UNIQUE)";

    public static final String CREATE_TASK_TABLE = 
            "CREATE TABLE " + TASK_TABLE + " (" + 
            TASK_ID         + " INTEGER PRIMARY KEY AUTOINCREMENT, " + 
            TASK_LIST_ID    + " INTEGER, " + 
            TASK_NAME       + " TEXT " + 
           )";

    public static final String DROP_LIST_TABLE = 
            "DROP TABLE IF EXISTS " + LIST_TABLE;

    public static final String DROP_TASK_TABLE = 
            "DROP TABLE IF EXISTS " + TASK_TABLE;

    private static class DBHelper extends SQLiteOpenHelper {

        public DBHelper(Context context, String name, 
                CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            // create tables
            db.execSQL(CREATE_LIST_TABLE);
            db.execSQL(CREATE_TASK_TABLE);

            // insert lists
            db.execSQL("INSERT INTO list VALUES (1, 'Hobbies')");
            db.execSQL("INSERT INTO list VALUES (2, 'Sports')");

            // insert sample tasks
            db.execSQL("INSERT INTO task VALUES (1, 1, 'Play the guitar')");
            db.execSQL("INSERT INTO task VALUES (2, 1, 'Play video games')");
        }

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

            Log.d("Task list", "Upgrading db from version " 
                    + oldVersion + " to " + newVersion);


            db.execSQL(MyDatabaseDB.DROP_LIST_TABLE);
            db.execSQL(MyDatabaseDB.DROP_TASK_TABLE);
            onCreate(db);
        }
    }

    // database object and database helper object
    private SQLiteDatabase db;
    private DBHelper dbHelper;

    // constructor
    public MyDatabaseDB(Context context) {
        dbHelper = new DBHelper(context, DB_NAME, null, DB_VERSION);
    }

    // private methods
    private void openReadableDB() {
        db = dbHelper.getReadableDatabase();
    }

    private void openWriteableDB() {
        db = dbHelper.getWritableDatabase();
    }

    private void closeDB() {
        if (db != null)
            db.close();
    }

    // public methods   

    public long insertTask(Task task) {
        ContentValues cv = new ContentValues();
        cv.put(TASK_LIST_ID, task.getListId());
        cv.put(TASK_NAME, task.getName());        

        this.openWriteableDB();
        long rowID = db.insert(TASK_TABLE, null, cv);
        this.closeDB();

        return rowID;
    }    

    public int updateTask(Task task) {
        ContentValues cv = new ContentValues();
        cv.put(TASK_LIST_ID, task.getListId());
        cv.put(TASK_NAME, task.getName());        

        String where = TASK_ID + "= ?";
        String[] whereArgs = { String.valueOf(task.getId()) };

        this.openWriteableDB();
        int rowCount = db.update(TASK_TABLE, cv, where, whereArgs);
        this.closeDB();

        return rowCount;
    }    

    public int deleteTask(long id) {
        String where = TASK_ID + "= ?";
        String[] whereArgs = { String.valueOf(id) };

        this.openWriteableDB();
        int rowCount = db.delete(TASK_TABLE, where, whereArgs);
        this.closeDB();

        return rowCount;
    }
}

This is a very reduced version of my class , built using some code I found on-line. In this example I'm only showing the code for two of my tables : List and Task, and just some of the sql methods for the Task table : insertTask,updateTask, and deleteTask.

Even though the code shown above works, I don't think it would be nice to have all the code for let's say ten tables all in the same class. So I tried to split all these code into several classes , one for each table. Something like this:

public class MyDatabaseDB {

    // database constants
    public static final String DB_NAME = "mydatabase.db";
    public static final int    DB_VERSION = 1;


    private static class DBHelper extends SQLiteOpenHelper {

        public DBHelper(Context context, String name, 
                CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            // create tables
            db.execSQL(ListDAL.CREATE_LIST_TABLE);
            db.execSQL(TaskDAL.CREATE_TASK_TABLE);

            // insert lists
            db.execSQL("INSERT INTO list VALUES (1, 'Hobbies')");
            db.execSQL("INSERT INTO list VALUES (2, 'Sports')");

            // insert sample tasks
            db.execSQL("INSERT INTO task VALUES (1, 1, 'Play the guitar')");
            db.execSQL("INSERT INTO task VALUES (2, 1, 'Play video games')");
        }

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

            Log.d("Task list", "Upgrading db from version " 
                    + oldVersion + " to " + newVersion);


            db.execSQL(ListDAL.DROP_LIST_TABLE);
            db.execSQL(TaskDAL.DROP_TASK_TABLE);
            onCreate(db);
        }
    }

    // database object and database helper object
    private SQLiteDatabase db;
    private DBHelper dbHelper;

    // constructor
    public MyDatabaseDB(Context context) {
        dbHelper = new DBHelper(context, DB_NAME, null, DB_VERSION);
    }

    // private methods
    private void openReadableDB() {
        db = dbHelper.getReadableDatabase();
    }

    private void openWriteableDB() {
        db = dbHelper.getWritableDatabase();
    }

    private void closeDB() {
        if (db != null)
            db.close();
    }   

}

These are the two new classes, the I created to put the code related to a specific table :

The ListDAL doesn't have much code

public class ListDAL {

   // list table constants
    public static final String LIST_TABLE = "list";

    public static final String LIST_ID = "_id";
    public static final int    LIST_ID_COL = 0;

    public static final String LIST_NAME = "list_name";
    public static final int    LIST_NAME_COL = 1;

    // CREATE and DROP TABLE statements
    public static final String CREATE_LIST_TABLE = 
            "CREATE TABLE " + LIST_TABLE + " (" + 
            LIST_ID   + " INTEGER PRIMARY KEY AUTOINCREMENT, " + 
            LIST_NAME + " TEXT    UNIQUE)";

    public static final String DROP_LIST_TABLE = 
            "DROP TABLE IF EXISTS " + LIST_TABLE;


}

The TaskDAL class is the one that contains most of the code, and it is in this class that I have problems, specifically in the insertTask,updateTask and deleteTask with calls like this.openWriteableDB(),this.openWriteableDB() or calls like db.insert(TASK_TABLE, null, cv).

Since these methods are no longer inside TaskDAL, I can't get access to them. I tried passing some references to these methods to be used in place of this or db, but it didn't work

public class TaskDAL {
    // task table constants
    public static final String TASK_TABLE = "task";

    public static final String TASK_ID = "_id";
    public static final int    TASK_ID_COL = 0;

    public static final String TASK_LIST_ID = "list_id";
    public static final int    TASK_LIST_ID_COL = 1;

    public static final String TASK_NAME = "task_name";
    public static final int    TASK_NAME_COL = 2; 

    // CREATE and DROP TABLE statements
    public static final String CREATE_TASK_TABLE = 
            "CREATE TABLE " + TASK_TABLE + " (" + 
            TASK_ID         + " INTEGER PRIMARY KEY AUTOINCREMENT, " + 
            TASK_LIST_ID    + " INTEGER, " + 
            TASK_NAME       + " TEXT " + 
           )";
    public static final String DROP_TASK_TABLE = 
            "DROP TABLE IF EXISTS " + TASK_TABLE;       

     // public methods   

    public long insertTask(Task task) {
        ContentValues cv = new ContentValues();
        cv.put(TASK_LIST_ID, task.getListId());
        cv.put(TASK_NAME, task.getName());        

        this.openWriteableDB();
        long rowID = db.insert(TASK_TABLE, null, cv);
        this.closeDB();

        return rowID;
    }    

    public int updateTask(Task task) {
        ContentValues cv = new ContentValues();
        cv.put(TASK_LIST_ID, task.getListId());
        cv.put(TASK_NAME, task.getName());        

        String where = TASK_ID + "= ?";
        String[] whereArgs = { String.valueOf(task.getId()) };

        this.openWriteableDB();
        int rowCount = db.update(TASK_TABLE, cv, where, whereArgs);
        this.closeDB();

        return rowCount;
    }    

    public int deleteTask(long id) {
        String where = TASK_ID + "= ?";
        String[] whereArgs = { String.valueOf(id) };

        this.openWriteableDB();
        int rowCount = db.delete(TASK_TABLE, where, whereArgs);
        this.closeDB();

        return rowCount;
    }
}

So, have any of you ever tried to so something similar?? If I managed to correctly separate the DB code into several classes, would I be still able to JOIN tables??

P.S. Please do not close this question, if you think I did something wrong please tell me and I'll try to correct it

Cambogia answered 28/8, 2014 at 13:11 Comment(5)
SQLiteOpenHelper manages the database, so you should have only one. Nothing prevents you from creating other classes.Selfimprovement
I know , but do you think you could give some hints on how to do it.Cambogia
@Cambogia Do you use a Content Provider ? In my apps, I decompose this code like that : one DBHelper, multiple PersistentContrat and one ContentProvider. It's clearly more readable. I can provide an example with your code if you wantTowle
@FrédéricLetellier Yes please :)Cambogia
@Cambogia Done ! Keep me informedTowle
K
5

do you think you could give some hints on how to do it

This has nothing much to do with Android, and even not all that much to do with Java. Decomposing long programming structures (e.g., classes in Java) into smaller structures has standard techniques, called design patterns, with language-specific implementations.

For example, you could go with the composite pattern:

  • Define an interface -- I'll call it TableHelper here -- that has onCreate() and onUpdate() methods that match those on SQLiteOpenHelper

  • Define N classes, one per table, that implement the TableHelper interface and provide the create and upgrade logic for that table (along with whatever other business logic you want to have on those classes)

  • Have your SQLiteOpenHelper define a TableHelper[] containing instances of your TableHelper classes, and have it delegate onCreate() and onUpgrade() to those TableHelper instances by iterating over the array

Krypton answered 28/8, 2014 at 13:57 Comment(5)
I'm interested in this question, but I haven't used delegates. Do you think you could explain a little bit more the last part about having the SQLiteOpenHelper define a TableHelper[]Saskatoon
@Axel: Have a static data member, of type TableHelper[]. Use a static initializer block to populate that array with instances of the TableHelper implementations. There's probably cleaner approaches than this using dependency injection (e.g., Dagger), but I have limited experience with DI. While not related to SQLiteOpenHelper, this sample activity shows a static ArrayList and initializer block.Krypton
@Krypton If I implement something as you described, will I still be able to JOIN tables??Cambogia
@eddy: JOIN is something that you do on a query. SQLiteOpenHelper is not involved with queries, other than to the extent that it sets up the tables that you do your queries against. Where you put your query code is up to you.Krypton
@Krypton I see, then I'll give it a try later and see what comes up. Thank you very muchCambogia
T
0

Using a Content Provider, you can split your long SQLiteOpenHelper in a multiple files : one persistenceContract for each table, one little SQLiteOpenHelper, and long and verbose ContentProvider.

With this solution, you need to write more code. But it's more readable, and easy to maintain.


Avantages :

  • Easy to name a column of a table when you write your query (example : TaskPersistenceContract.TaskEntry.COLUMN_TASK_NAME)
  • Easy to read and maintain
  • Less typo bugs
  • Use cursor and CursorLoader logic

Disadvantage :

  • More verbose

Let's try with your initial code !

1. Create a PersistenceContract for each table

ListPersistenceContract :

public final class ListPersistenceContract {

    public static final String CONTENT_AUTHORITY = BuildConfig.APPLICATION_ID;
    public static final String CONTENT_LIST_TYPE = "vnd.android.cursor.dir/" + CONTENT_AUTHORITY + "/" + ListEntry.TABLE_NAME;
    public static final String CONTENT_LIST_ITEM_TYPE = "vnd.android.cursor.item/" + CONTENT_AUTHORITY + "/" + ListEntry.TABLE_NAME;
    public static final String VND_ANDROID_CURSOR_ITEM_VND = "vnd.android.cursor.item/vnd." + CONTENT_AUTHORITY + ".";
    private static final String CONTENT_SCHEME = "content://";
    public static final Uri BASE_CONTENT_URI = Uri.parse(CONTENT_SCHEME + CONTENT_AUTHORITY);
    private static final String VND_ANDROID_CURSOR_DIR_VND = "vnd.android.cursor.dir/vnd." + CONTENT_AUTHORITY + ".";
    private static final String SEPARATOR = "/";

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

    public static Uri getBaseListUri(String listId) {
        return Uri.parse(CONTENT_SCHEME + CONTENT_LIST_ITEM_TYPE + SEPARATOR + listId);
    }

    /* Inner class that defines the table contents */
    public static abstract class ListEntry implements BaseColumns {

        public static final String TABLE_NAME = "list";
        public static final String COLUMN_LIST_NAME = "list_name";

        public static final Uri CONTENT_LIST_URI = BASE_CONTENT_URI.buildUpon().appendPath(TABLE_NAME).build();
        public static String[] LIST_COLUMNS = new String[]{
                ListPersistenceContract.ListEntry._ID,
                ListEntry.COLUMN_LIST_NAME};

        public static final String LIST_AND_TASK = "listandtask";

        public static Uri buildListUriWith(long id) {
            return ContentUris.withAppendedId(CONTENT_LIST_URI, id);
        }

        public static Uri buildListUriWith(String id) {
            Uri uri = CONTENT_LIST_URI.buildUpon().appendPath(id).build();
            return uri;
        }

        public static Uri buildListUri() {
            return CONTENT_LIST_URI.buildUpon().build();
        }

        public static Uri buildListAndTaskUri() {
            return BASE_CONTENT_URI.buildUpon().appendPath(ListEntry.LIST_AND_TASK).build();
        }

    }
}

TaskPersistenceContract :

public class TaskPersistenceContract {

    public static final String CONTENT_AUTHORITY = BuildConfig.APPLICATION_ID;
    public static final String CONTENT_TASK_TYPE = "vnd.android.cursor.dir/" + CONTENT_AUTHORITY + "/" + TaskEntry.TABLE_NAME;
    public static final String CONTENT_TASK_ITEM_TYPE = "vnd.android.cursor.item/" + CONTENT_AUTHORITY + "/" + TaskEntry.TABLE_NAME;
    public static final String VND_ANDROID_CURSOR_ITEM_VND = "vnd.android.cursor.item/vnd." + CONTENT_AUTHORITY + ".";
    private static final String CONTENT_SCHEME = "content://";
    public static final Uri BASE_CONTENT_URI = Uri.parse(CONTENT_SCHEME + CONTENT_AUTHORITY);
    private static final String VND_ANDROID_CURSOR_DIR_VND = "vnd.android.cursor.dir/vnd." + CONTENT_AUTHORITY + ".";
    private static final String SEPARATOR = "/";

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

    public static Uri getBaseTaskUri(String taskId) {
        return Uri.parse(CONTENT_SCHEME + CONTENT_TASK_ITEM_TYPE + SEPARATOR + taskId);
    }

    /* Inner class that defines the table contents */
    public static abstract class TaskEntry implements BaseColumns {

        public static final String TABLE_NAME = "task";
        public static final String COLUMN_TASK_LIST_ID = "list_id";
        public static final String COLUMN_TASK_NAME = "task_name";


        public static final Uri CONTENT_TASK_URI = BASE_CONTENT_URI.buildUpon().appendPath(TABLE_NAME).build();
        public static String[] TASK_COLUMNS = new String[]{
                TaskPersistenceContract.TaskEntry._ID,
                TaskPersistenceContract.TaskEntry.COLUMN_TASK_LIST_ID,
                TaskPersistenceContract.TaskEntry.COLUMN_TASK_NAME};

        public static Uri buildTaskUriWith(long id) {
            return ContentUris.withAppendedId(CONTENT_TASK_URI, id);
        }

        public static Uri buildTaskUriWith(String id) {
            Uri uri = CONTENT_TASK_URI.buildUpon().appendPath(id).build();
            return uri;
        }

        public static Uri buildTaskUri() {
            return CONTENT_TASK_URI.buildUpon().build();
        }

    }
}

2. Create DbHelper

public class LocalDbHelper {

    public static final int DB_VERSION = 1;
    public static final String DB_NAME = "mydatabase.db";
    private static final String TEXT_TYPE = " TEXT";
    private static final String INTEGER_TYPE = " INTEGER";
    private static final String PRIMARY_KEY = " PRIMARY KEY";
    private static final String AUTOINCREMENT = " AUTOINCREMENT";
    private static final String UNIQUE = " UNIQUE";
    private static final String CREATE_TABLE = "CREATE TABLE ";
    private static final String DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS ";
    private static final String OPEN_PARENTHESIS = " (";
    private static final String CLOSE_PARENTHESIS = " )";
    private static final String COMMA_SEP = ",";

    private static final String CREATE_LIST_TABLE =
            CREATE_TABLE + ListPersistenceContract.ListEntry.TABLE_NAME + OPEN_PARENTHESIS +
                    ListPersistenceContract.ListEntry._ID + INTEGER_TYPE + PRIMARY_KEY + AUTOINCREMENT + COMMA_SEP +
                    ListPersistenceContract.ListEntry.COLUMN_LIST_NAME + TEXT_TYPE + UNIQUE +
                    CLOSE_PARENTHESIS;

    private static final String CREATE_TASK_TABLE =
            CREATE_TABLE + TaskPersistenceContract.TaskEntry.TABLE_NAME + OPEN_PARENTHESIS +
                    TaskPersistenceContract.TaskEntry._ID + INTEGER_TYPE + PRIMARY_KEY + AUTOINCREMENT + COMMA_SEP +
                    TaskPersistenceContract.TaskEntry.COLUMN_TASK_LIST_ID + INTEGER_TYPE + COMMA_SEP +
                    TaskPersistenceContract.TaskEntry.COLUMN_TASK_NAME + TEXT_TYPE +
                    CLOSE_PARENTHESIS;

    private static final String DROP_LIST_TABLE =
            DROP_TABLE_IF_EXISTS + ListPersistenceContract.ListEntry.TABLE_NAME;

    private static final String DROP_TASK_TABLE =
            DROP_TABLE_IF_EXISTS + TaskPersistenceContract.TaskEntry.TABLE_NAME;

    public LocalDbHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    public void onCreate(SQLiteDatabase db) {
        // create tables
        db.execSQL(CREATE_LIST_TABLE);
        db.execSQL(CREATE_TASK_TABLE);

        // insert lists
        db.execSQL("INSERT INTO " + ListPersistenceContract.ListEntry.TABLE_NAME + " VALUES (1, 'Hobbies')");
        db.execSQL("INSERT INTO " + ListPersistenceContract.ListEntry.TABLE_NAME + " VALUES (2, 'Sports')");

        // insert sample tasks
        db.execSQL("INSERT INTO " + TaskPersistenceContract.TaskEntry.TABLE_NAME + " VALUES (1, 1, 'Play the guitar')");
        db.execSQL("INSERT INTO " + TaskPersistenceContract.TaskEntry.TABLE_NAME + " VALUES (2, 1, 'Play video games')");
    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d("Task list", "Upgrading db from version "
                + oldVersion + " to " + newVersion);


        db.execSQL(LocalDbHelper.DROP_LIST_TABLE);
        db.execSQL(LocalDbHelper.DROP_TASK_TABLE);
        onCreate(db);
    }

    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Not required as at version 1
    }
}

3. Create ContentProvider with query, insert, update and delete operations

(in this example, i put a join of tables for a query. You can use the same logic for your insert, update and delete operations.)

public class MyAppContentProvider extends ContentProvider {

    private static final int LIST = 100;
    private static final int LIST_ITEM = 101;
    private static final int LIST_AND_TASK = 102;
    private static final int TASK = 200;
    private static final int TASK_ITEM = 201;

    private static final UriMatcher sUriMatcher = buildUriMatcher();
    private LocalDbHelper mLocalDbHelper;

    private static final SQLiteQueryBuilder sListAndTask;

    static{
        sListAndTask = new SQLiteQueryBuilder();

        sListAndTask.setTables(
                ListPersistenceContract.ListEntry.TABLE_NAME + " INNER JOIN " +
                        TaskPersistenceContract.TaskEntry.TABLE_NAME +
                        " ON " + ListPersistenceContract.ListEntry.TABLE_NAME +
                        "." + ListPersistenceContract.ListEntry._ID +
                        " = " + TaskPersistenceContract.TaskEntry.TABLE_NAME +
                        "." + TaskPersistenceContract.TaskEntry.COLUMN_TASK_LIST_ID);
    }

    private static UriMatcher buildUriMatcher() {
        final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
        final String authority = ListPersistenceContract.CONTENT_AUTHORITY;

        matcher.addURI(authority, ListPersistenceContract.ListEntry.TABLE_NAME, LIST);
        matcher.addURI(authority, ListPersistenceContract.ListEntry.TABLE_NAME + "/*", LIST_ITEM);
        matcher.addURI(authority, ListPersistenceContract.ListEntry.LIST_AND_TASK, LIST_AND_TASK);

        matcher.addURI(authority, TaskPersistenceContract.TaskEntry.TABLE_NAME, TASK);
        matcher.addURI(authority, TaskPersistenceContract.TaskEntry.TABLE_NAME + "/*", TASK_ITEM);

        return matcher;
    }

    @Override
    public boolean onCreate() {
        mLocalDbHelper = new LocalDbHelper(getContext());
        return true;
    }

    @Nullable
    @Override
    public String getType(Uri uri) {
        final int match = sUriMatcher.match(uri);
        switch (match) {
            case LIST:
                return ListPersistenceContract.CONTENT_LIST_TYPE;
            case LIST_ITEM:
                return ListPersistenceContract.CONTENT_LIST_ITEM_TYPE;
            case TASK:
                return TaskPersistenceContract.CONTENT_TASK_TYPE;
            case TASK_ITEM:
                return TaskPersistenceContract.CONTENT_TASK_ITEM_TYPE;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Cursor retCursor;
        switch (sUriMatcher.match(uri)) {
            case LIST:
                retCursor = mLocalDbHelper.getReadableDatabase().query(
                        ListPersistenceContract.ListEntry.TABLE_NAME,
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder
                );
                break;
            case LIST_ITEM:
                String[] where_list = {uri.getLastPathSegment()};
                retCursor = mLocalDbHelper.getReadableDatabase().query(
                        ListPersistenceContract.ListEntry.TABLE_NAME,
                        projection,
                        ListPersistenceContract.ListEntry._ID + " = ?",
                        where_list,
                        null,
                        null,
                        sortOrder
                );
                break;
            case LIST_AND_TASK:
                retCursor = sListAndTask.query(mLocalDbHelper.getReadableDatabase(),
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder
                );
                break;
            case TASK:
                retCursor = mLocalDbHelper.getReadableDatabase().query(
                        TaskPersistenceContract.TaskEntry.TABLE_NAME,
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder
                );
                break;
            case TASK_ITEM:
                String[] where_task = {uri.getLastPathSegment()};
                retCursor = mLocalDbHelper.getReadableDatabase().query(
                        TaskPersistenceContract.TaskEntry.TABLE_NAME,
                        projection,
                        TaskPersistenceContract.TaskEntry._ID + " = ?",
                        where_task,
                        null,
                        null,
                        sortOrder
                );
                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        retCursor.setNotificationUri(getContext().getContentResolver(), uri);
        return retCursor;
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        final SQLiteDatabase db = mLocalDbHelper.getWritableDatabase();
        final int match = sUriMatcher.match(uri);
        Uri returnUri;
        Cursor exists;

        switch (match) {
            case LIST:
                exists = db.query(
                        ListPersistenceContract.ListEntry.TABLE_NAME,
                        new String[]{ListPersistenceContract.ListEntry._ID},
                        ListPersistenceContract.ListEntry._ID + " = ?",
                        new String[]{values.getAsString(ListPersistenceContract.ListEntry._ID)},
                        null,
                        null,
                        null
                );
                if (exists.moveToLast()) {
                    long _id = db.update(
                            ListPersistenceContract.ListEntry.TABLE_NAME, values,
                            ListPersistenceContract.ListEntry._ID + " = ?",
                            new String[]{values.getAsString(ListPersistenceContract.ListEntry._ID)}
                    );
                    if (_id > 0) {
                        returnUri = ListPersistenceContract.ListEntry.buildListUriWith(_id);
                    } else {
                        throw new android.database.SQLException("Failed to insert row into " + uri);
                    }
                } else {
                    long _id = db.insert(ListPersistenceContract.ListEntry.TABLE_NAME, null, values);
                    if (_id > 0) {
                        returnUri = ListPersistenceContract.ListEntry.buildListUriWith(_id);
                    } else {
                        throw new android.database.SQLException("Failed to insert row into " + uri);
                    }
                }
                exists.close();
                break;
            case TASK:
                exists = db.query(
                        TaskPersistenceContract.TaskEntry.TABLE_NAME,
                        new String[]{TaskPersistenceContract.TaskEntry._ID},
                        TaskPersistenceContract.TaskEntry._ID + " = ?",
                        new String[]{values.getAsString(TaskPersistenceContract.TaskEntry._ID)},
                        null,
                        null,
                        null
                );
                if (exists.moveToLast()) {
                    long _id = db.update(
                            TaskPersistenceContract.TaskEntry.TABLE_NAME, values,
                            TaskPersistenceContract.TaskEntry._ID + " = ?",
                            new String[]{values.getAsString(TaskPersistenceContract.TaskEntry._ID)}
                    );
                    if (_id > 0) {
                        returnUri = TaskPersistenceContract.TaskEntry.buildTaskUriWith(_id);
                    } else {
                        throw new android.database.SQLException("Failed to insert row into " + uri);
                    }
                } else {
                    long _id = db.insert(TaskPersistenceContract.TaskEntry.TABLE_NAME, null, values);
                    if (_id > 0) {
                        returnUri = TaskPersistenceContract.TaskEntry.buildTaskUriWith(_id);
                    } else {
                        throw new android.database.SQLException("Failed to insert row into " + uri);
                    }
                }
                exists.close();
                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return returnUri;

    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        final SQLiteDatabase db = mLocalDbHelper.getWritableDatabase();
        final int match = sUriMatcher.match(uri);
        int rowsDeleted;

        switch (match) {
            case LIST:
                rowsDeleted = db.delete(
                        ListPersistenceContract.ListEntry.TABLE_NAME, selection, selectionArgs);
                break;
            case TASK:
                rowsDeleted = db.delete(
                        TaskPersistenceContract.TaskEntry.TABLE_NAME, selection, selectionArgs);
                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        if (selection == null || rowsDeleted != 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return rowsDeleted;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        final SQLiteDatabase db = mLocalDbHelper.getWritableDatabase();
        final int match = sUriMatcher.match(uri);
        int rowsUpdated;

        switch (match) {
            case LIST:
                rowsUpdated = db.update(ListPersistenceContract.ListEntry.TABLE_NAME, values, selection,
                        selectionArgs
                );
                break;
            case TASK:
                rowsUpdated = db.update(TaskPersistenceContract.TaskEntry.TABLE_NAME, values, selection,
                        selectionArgs
                );
                break;
            default:
                throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        if (rowsUpdated != 0) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
        return rowsUpdated;
    }
}
Towle answered 27/10, 2016 at 15:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.