I'm creating a number of custom content providers for a client and on one of the screens we want to show the count of some of the tables.
Now in sql world that would be easy, simply run a query that is
select count(_id) from cartable
But in content provider world, it's a bit harder. After stumbling around a bit playing with provider.call methods,
Now just like you can tell the content provider to give you an instance of a car by id like this:
content://find.me.a.car/car/123
You can define a new URI format and use that to have the content provider's query method do something other than return a cursor that contains a
list or a single row. You can have it return a cursor that is a count.
Here's our test method. Since it's a test, we're inserting a record first then getting the count of the table. The URI would look something like
content://find.me.a.car/car/COUNT
public void testCountCall(){ Log.d(TAG, "--------------testInsert()-------------"); ContentProvider provider = getProvider(); Log.d(TAG, "Running insert of new Car record"); Car obj = createObject(); mUriRInsert=provider.insert(ProviderHelper.determineURI(obj), obj.createContentValues()); Log.d(TAG, "Content inserted at: " + mUriRInsert); Log.d(TAG, "------- testinsert will complete successfully if the returned uri is not null"); Uri uriCount = Uri.withAppendedPath(ProviderConstants.CAR_CONTENT_URI, "COUNT"); Cursor c = provider.query( uriCount, null, null, null, null); c.moveToFirst(); int count = c.getInt(0); Log.d(TAG, "new Count:" + count); assertEquals(1, count); }
--- NEXT STEP: Define a pattern for the COUNT in your provider
The first two are standard, the third pattern will match the count.
static { sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(ProviderConstants.CAR_AUTHORITY, ProviderConstants.CAR_PATH, ProviderConstants.CP_TYPE_LIST); sUriMatcher.addURI(ProviderConstants.CAR_AUTHORITY, ProviderConstants.CAR_PATH+"/#", ProviderConstants.CP_TYPE_ITEM); sUriMatcher.addURI(ProviderConstants.CAR_AUTHORITY, ProviderConstants.CAR_PATH+"/COUNT", ProviderConstants.CP_TYPE_COUNT); }
----------- Third Step: Modify the query() method of the provider so it knows what to do with a URI that matches the COUNT
@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Log.d(TAG, "uri:" +uri); Log.d(TAG, "where:" +selection); SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); switch (sUriMatcher.match(uri)) { case ProviderConstants.CP_TYPE_LIST: builder.setTables(TABLENAME); builder.setProjectionMap(sDataProjectionMap); break; case ProviderConstants.CP_TYPE_ITEM: builder.setTables(TABLENAME); builder.setProjectionMap(sDataProjectionMap); builder.appendWhere(DatabaseConstants.F__ID + " = " + uri.getPathSegments().get(1)); break; case ProviderConstants.CP_TYPE_COUNT: builder.setTables(TABLENAME); HashMap<String, String> countMap = new HashMap<String, String>(); countMap.put("count", "count(*)"); builder.setProjectionMap(countMap); break; default: throw new IllegalArgumentException("Unknown URI: " + uri); } Cursor queryCursor = mDBHelper.runQueryBuilder(builder, projection, selection, selectionArgs, null, null, null); queryCursor.setNotificationUri(getContext().getContentResolver(), uri); return queryCursor; }
Pretty straightforward and very handy.
No comments:
Post a Comment