Calling delete method in custom content provider

Jeff picture Jeff · Mar 11, 2011 · Viewed 24.4k times · Source

I am learning Android and I am stuck on an issue involving calling a custom content provider. I have been using an example in an instructional book and although it describes how to create the custom provider there is no clear example how to call the specific methods in it. I am specifically looking into how to delete a single record from the custom content provider.

Here is the code for the custom content provider (EarthquakeProvider.java):

@Override


public int delete(Uri uri, String where, String[] whereArgs) {
int count;

switch (uriMatcher.match(uri)) {
  case QUAKES:
    count = earthquakeDB.delete(EARTHQUAKE_TABLE, where, whereArgs);
    break;

  case QUAKE_ID:
    String segment = uri.getPathSegments().get(1);
    count = earthquakeDB.delete(EARTHQUAKE_TABLE, KEY_ID + "="
                                + segment
                                + (!TextUtils.isEmpty(where) ? " AND (" 
                                + where + ')' : ""), whereArgs);
    break;

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

getContext().getContentResolver().notifyChange(uri, null);
return count;


 }

I am trying to call the delete method from the main activity to delete a single entry, not the entire database. I want to use about an OnLongClickListener for the selected record that is displayed in a array list view in the main activity.

This is what I have come up with I have so far in my main activity for this method:

earthquakeListView.setOnItemLongClickListener(new OnItemLongClickListener() {

    @Override
    public boolean onItemLongClick(AdapterView _av, View _v, int _index,
            long arg3) {
        ContentResolver cr = getContentResolver();
        cr.delete(earthquakeProvider.CONTENT_URI, null, null); 

        return false;
    }

I know the above code doesn't work, but this is as close as I could get with my current understanding.

Any help on this would be very much appreciated.

Answer

jcwenger picture jcwenger · Mar 11, 2011
cr.delete(earthquakeProvider.CONTENT_URI, null, null);

This is your problem. First, some context:

Content URIs: (source)

content://authority/path/##

The number at the end is optional. If present, the URI references a specific row in the database where row._id=(the number). If absent, it references the table as a whole.

the delete() call accepts a URI, a where clause, and a set of strings which get substituted in. Example: Say you have a database of people.

cr.delete(
   Person.CONTENT_URI, 
   "sex=? AND eyecolor=?", 
   new String[]{"male", "blue"});

Will search the entire person table, and delete anyone whose sex is male and whose eye color is blue.

If the where clause and where values are null, then the delete() call will match every row in the table. This causes the behavior you see.

There are two methods to specify the row you want:

First option, you could append the number to the URI:

cr.delete(
    EarthquakeProvider.CONTENT_URI.buildUpon().appendPath(String.valueOf(_id)).build(),
    null, null);

This restricts the URI to a specific row, and the path will be through your case QUAKE_ID: statement and so will only delete one row no matter what.

Second option, you could use a where clause:

cr.delete(EarthquakeProvider.CONTENT_URI, "_id=?", String.valueOf(_id)));

Either way, you will restrict the delete to a single row, as you need it to. The latter makes for prettier code, but the former is more efficient, due to the way the ContentProvider and ContentObservers work.

As a last note: In your ContentProvider you need to add a call to ContentResolver.notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork). This helps notify cursors to re-fetch the database query and helps out a lot with automation.