Calling delete method in custom content provider
Asked Answered
A

1

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.

Acidimetry answered 10/3, 2011 at 23:46 Comment(0)
F
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.

Fusco answered 11/3, 2011 at 19:19 Comment(10)
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/3Fusco
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...?Acidimetry
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.Acidimetry
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.Fusco
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!Acidimetry
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. :)Fusco
I want to add that if the CursorAdapter is managed by a LoaderManager.LoaderCallbacks<Cursor> you should call restartLoader() to get the ListView refreshed.Power
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.Broil
@Broil look at https://mcmap.net/q/167756/-how-to-delete-from-a-table-where-id-is-in-a-list-of-ids and do some footwork yourself.Fusco
@Fusco :D did the footwork , got the answers :) , thanks anywaysBroil

© 2022 - 2024 — McMap. All rights reserved.