Friday, June 22, 2012

Content Provider and Count queries


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