12

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.

Macarse
  • 87,001
  • 42
  • 169
  • 229
Jeff
  • 139
  • 1
  • 2
  • 6

1 Answers1

26
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.

jcwenger
  • 11,254
  • 1
  • 50
  • 63
  • Also, in your ContentProvider code, uri.getPathSegments().get(1) is wrong. Since the row id is always last in the URI, you want: uri.getLastPathSegment() -- uri.getPathSegments().get(1) will get you the path after the first slash. Think of what it does in the case of content://com.example.transportationprovider/land/bus/3 – jcwenger Mar 11 '11 at 19:24
  • Thank you, I made the changes using the first suggested code. I am getting a fatal error when I run it in the emulator: java.lang.IllegalArgumentException: Unsupported URI: content://com.paad.provider.earthquake/earthquakes/1. This should be the correct URI but its not work...? – Jeff Mar 12 '11 at 20:43
  • This is from the LOGCAT: ERROR/AndroidRuntime(370): FATAL EXCEPTION: main ERROR/AndroidRuntime(370): java.lang.IllegalArgumentException: Unsupported URI: content://com.paad.provider.earthquake/earthquakes/1 ERROR/AndroidRuntime(370): at com.paad.earthquake.EarthquakeProvider.delete(EarthquakeProvider.java:103). Line 103 is the 'default: throw new Illegal...' line in the earthquakeProvider. I can copy the entire error log but it wont fit in the comment section. – Jeff Mar 12 '11 at 23:29
  • Right. So, URI matcher isn't working. You need it to match a uri with number attached. You need something like: uriMatcher.addURI(AUTHORITY, EarthquakeProvider.CONTENT_URI.toString+"/#", QUAKE_ID); -- It's not finding your uri in the list of things your uriMatcher is looking for, so your second case block is never called. That's a separate problem from your initial question. – jcwenger Mar 13 '11 at 02:15
  • Ok, it's working now. Thank you so much for your help. I figured out what was wrong: I was calling "com.paad.provider.earthquake" and in the URI matcher it was listed as "com.paad.provider.Earthquake". Ah, case sensitivity! – Jeff Mar 13 '11 at 15:26
  • Glad I could help. If all your question is answered, can you mark it as such? It's the check mark button in the left margin. That closes the question as complete (and scores me some reputation for my work. :) – jcwenger Mar 13 '11 at 17:22
  • I want to add that if the CursorAdapter is managed by a LoaderManager.LoaderCallbacks you should call restartLoader() to get the ListView refreshed. – gsscoder Dec 09 '12 at 06:51
  • what If I want to delete multiple entries with say where `id = 1 or 3 or 7 or 8` but I don't want to call `delete` queries **four times** here. – eRaisedToX May 11 '17 at 11:01
  • @eRaisedToX look at http://stackoverflow.com/questions/2615566/delete-where-id-in-list and do some footwork yourself. – jcwenger May 11 '17 at 14:49
  • @jcwenger :D did the footwork , got the answers :) , thanks anyways – eRaisedToX May 11 '17 at 16:57