Search code examples
androidsqliteandroid-contentprovider

Use Insert or Replace in ContentProvider


When I want to check and see if something exists in my ContentProvider what I usually do is something similar to this

Cursor c = getContentResolver().query(table,projection,selection,selectionArgs,sort);

if(c != null && c.moveToFirst()){

    //item exists so update

}else{

    //item does not exist so insert

}

but that means I always have to make possibly an unnecessary Database call slowing things down especially the greater number of checks on the database I need to do. There has to be a better way to handle this so I dont always have to query first.

I looked at this question

Android Contentprovider - update within an insert method

but using insertWithOnConflict only checks the primary key id and in my case that will not work because what I am checking is not the id but a unique string from a server database.

so is there something I can do with the Content Provider so I dont always have to make a query to check if the item exists in it already?


Solution

  • You can have UNIQUE constraint on columns different than ID one. Example:

    CREATE TABLE TEST (_id INTEGER PRIMARY KEY AUTOINCREMENT, server_id INTEGER NOT NULL, name TEXT, UNIQUE(server_id))

    Having this table, in the insert method of your Content Provider you can do something like this:

    @Override
        public Uri insert(Uri uri, ContentValues contentValues) {
            final SQLiteDatabase db = mDatabase.getWritableDatabase();
            final int match = mUriMathcer.match(uri);
            switch (match) {
                case TEST:
                    insertOrUpdateById(db, uri, "TEST",
                            contentValues, "server_id");
                    getContext().getContentResolver().notifyChange(uri, null, false);
                    return Contract.Test.buildTestUri(contentValues.getAsString("server_id"));
                default:
                    throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        }
    
    /**
     * In case of a conflict when inserting the values, another update query is sent.
     *
     * @param db     Database to insert to.
     * @param uri    Content provider uri.
     * @param table  Table to insert to.
     * @param values The values to insert to.
     * @param column Column to identify the object.
     * @throws android.database.SQLException
     */
    private void insertOrUpdateById(SQLiteDatabase db, Uri uri, String table,
                                    ContentValues values, String column) throws SQLException {
        try {
            db.insertOrThrow(table, null, values);
        } catch (SQLiteConstraintException e) {
            int nrRows = update(uri, values, column + "=?",
                    new String[]{values.getAsString(column)});
            if (nrRows == 0)
                throw e;
        }
    }
    

    I hope it helps. Cheers!