Own ContentProvider with SQLite and multiple tables
Asked Answered
B

3

11

I am reading this tutorial on implementing my own ContentProvide for working with SQLite. Int the ContentProvider.query there are a few thing that puzzles me. It seems very hardcoded to just one table (the todo table in the tutorial), but maybe Im just not getting it? Now if I wanted to query another table, lets say nodo, how would I change the ContentProvider?

Should I append the table names somehow in queryBuilder.setTables(String inTables)?

What about the CONTENT_TYPE and CONTENT_ITEM_TYPE, should there be one for each table?

That about the TODO and TODO_ID varibles and the switch in the query method?

It seems I need to have a lot of if/switch conditions to support multiple tables with the same ContentProvider, is this the way to go or am I on a wrong path?

Thank you
Søren

Bonnett answered 26/11, 2012 at 20:10 Comment(1)
1. setTables... It depends on your needs if you need join you should but still point 2... 2. Content mime... Yes 3. Again for every table. 4. Wrong path... No i think that a good path... You can try to search/write some kind of generator fx selvin.pl/autocontent.zip <= its mine but its not support views yet only TablesApostles
G
27

Now if I wanted to query another table, lets say nodo, how would I change the ContentProvider?

Querying a new table would mean that you need to add a new Uri, since the Uri selects the datasource, similar to using a different table.

You would be adding essentially all the hardcoded values that are already there for the todos for your other table. For example:

// ------- usually the same for all
private static final String AUTHORITY = "de.vogella.android.todos.contentprovider";

// ------- define some Uris
private static final String PATH_TODOS = "todos";
private static final String PATH_REMINDERS = "reminders";

public static final Uri CONTENT_URI_TODOS = Uri.parse("content://" + AUTHORITY
    + "/" + PATH_TODOS);
public static final Uri CONTENT_URI_REMINDERS = Uri.parse("content://" + AUTHORITY
        + "/" + PATH_REMINDERS);

// ------- maybe also define CONTENT_TYPE for each

// ------- setup UriMatcher
private static final int TODOS = 10;
private static final int TODO_ID = 20;
private static final int REMINDERS = 30;
private static final int REMINDERS_ID = 40;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
  sURIMatcher.addURI(AUTHORITY, PATH_TODOS, TODOS);
  sURIMatcher.addURI(AUTHORITY, PATH_TODOS + "/#", TODO_ID);
  sURIMatcher.addURI(AUTHORITY, PATH_REMINDERS, REMINDERS);
  sURIMatcher.addURI(AUTHORITY, PATH_REMINDERS + "/#", REMINDERS_ID);
}

//@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {

    // Using SQLiteQueryBuilder instead of query() method
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

    int uriType = sURIMatcher.match(uri);
    switch (uriType) {

        case TODO_ID:
            // Adding the ID to the original query
            queryBuilder.appendWhere(TodoTable.COLUMN_ID + "="
                    + uri.getLastPathSegment());
            //$FALL-THROUGH$
        case TODOS:
            queryBuilder.setTables(TodoTable.TABLE_TODO);
            break;

        case REMINDERS_ID:
            // Adding the ID to the original query
            queryBuilder.appendWhere(ReminderTable.COLUMN_ID + "="
                    + uri.getLastPathSegment());
            //$FALL-THROUGH$
        case REMINDERS:
            queryBuilder.setTables(ReminderTable.TABLE_REMINDER);
            break;

        default:
            throw new IllegalArgumentException("Unknown URI: " + uri);
  }

Should I append the table names somehow in queryBuilder.setTables(String inTables)?

Yes, if different Uris read from different tables then set the table based on the Uri match.

What about the CONTENT_TYPE and CONTENT_ITEM_TYPE, should there be one for each table?

Depends on the actual content type. If they are different and you need a type yes. But you don't need to have them at all. That example defines them but doesn't even use them. It would need to return the type in getType, see documentation.

That about the TODO and TODO_ID varibles and the switch in the query method?

Those are constants defined for the UriMatcher which is explained nicely here. It's basically a simplification for String matching. A big ContentProvider can have 100 different Uris and selecting the right table in query would be painful if you would have to write if (uri.getPath().equals("todos") { /* code */ } else if (uri.. all the way.

Guadalajara answered 26/11, 2012 at 21:16 Comment(1)
hi, how would you implement the delete method in this case? can you please help?Slocum
S
1

Here's solution to your question, using UriMatcher, you can implement multiple tables in a content provider.

Samarium answered 8/2, 2013 at 19:10 Comment(0)
G
0

Content type and content item can be as follows and they can be wrapped in a separate class for each table

public static final String GENERAL_CONTENT_TYPE = "vnd.android.cursor.dir/vnd.myfirstapp.db.member" ; public static final String SPECIFIC_CONTENT_TYPE = "vnd.android.cursor.item/vnd.myfirstapp.db.member" ;

`vnd.android.cursor.dir/vnd.yourownanything.anything.tablename'

this defines the general content type `vnd.android.cursor.item/vnd.anthingasabove.table' this also defines the specific and it is constant to any app those strings(words) vnd.android.cursor.dir and .item must be like that and after /vnd. must be like that

and in the class that extends contentprovider you just uset the same instance of UriMatcher to map the tables

Gatt answered 21/2, 2014 at 17:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.