So I'm getting an unreachable statement in the following switch statement. I can't figure out why this is happening, any help would be much appreciated.
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = psHelper.getWritableDatabase();
int delCount = 0;
return 0;
switch (URI_MATCHER.match(uri)) {
case PRODUCT_LIST:
// THE LINE BELOW IS UNREACHABLE
delCount = db.delete(TABLE_NAME_PRODUCTS, selection, selectionArgs);
break;
case PRODUCT_ID:
String idStr = uri.getLastPathSegment();
String where = PSContract.Products.ID_COLUMN + " = " + idStr;
if (!TextUtils.isEmpty(selection)) {
where += " AND " + selection;
}
delCount = db.delete(TABLE_NAME_PRODUCTS, where, selectionArgs);
break;
case SUPPLIER_LIST:
delCount = db.delete(TABLE_NAME_SUPPLIERS, selection, selectionArgs);
break;
case SUPPLIER_ID:
String idStr2 = uri.getLastPathSegment();
String where2 = PSContract.Products.ID_COLUMN + " = " + idStr2;
if (!TextUtils.isEmpty(selection)) {
where2 += " AND " + selection;
}
delCount = db.delete(TABLE_NAME_SUPPLIERS, where2, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return delCount;
}
You're returning 0 right before the switch. There is no way that the switch can be reached if you return from the method right before, so the error is generated.
Under int delCount = 0 you are returning 0 which is going end the function call. Since that return is in a place where it will happen 100% of the time nothing below it will ever execute. Looks like a typo to me.
Related
When I try to update my data I get this error
java.lang.IllegalArgumentException: Update is not supported for content://com.example.recodedharran.booksinventory/books/3
I used the debugger and the match value appears to be -1 !
public int update(Uri uri, ContentValues contentValues, String selection,
String[] selectionArgs) {
final int match = sUriMatcher.match(uri);
switch (match) {
case BOOKS:
return updateBook(uri, contentValues, selection, selectionArgs);
case BOOKS_ID:
// For the PET_ID code, extract out the ID from the URI,
// so we know which row to update. Selection will be "_id=?" and selection
// arguments will be a String array containing the actual ID.
selection = BooksContract.BooksEntry._ID + "=?";
selectionArgs = new String[]{String.valueOf(ContentUris.parseId(uri))};
return updateBook(uri, contentValues, selection, selectionArgs);
default:
throw new IllegalArgumentException("Update is not supported for " + uri);
}
}
private int updateBook(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
if (values.containsKey(BooksContract.BooksEntry.COLUMN_PRODUCT_NAME)) {
String name = values.getAsString(BooksContract.BooksEntry.COLUMN_PRODUCT_NAME);
if (name == null) {
throw new IllegalArgumentException("Pet requires a name");
}
if (values.size() == 0) {
return 0;
}
}
SQLiteDatabase database = mDbHelper.getReadableDatabase();
int rowsUpdated = database.update(BooksContract.BooksEntry.TABLE_NAME, values, selection, selectionArgs);
// If 1 or more rows were updated, then notify all listeners that the data at the
// given URI has changed
if (rowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of rows updated
return rowsUpdated;
}
you are throwing this Exception here.
default:
throw new IllegalArgumentException("Update is not supported for " + uri);
It's clear that match does not equal the value in both cases (BOOKS_ID, BOOK)
check that (BOOKS_ID, BOOKS) always satisfy the switch statement or remove or change the
default:
throw new IllegalArgumentException("Update is not supported for " + uri);
to
default: return -1; //return `-1` for example or any integer that gives a relevant indication.
Here, this was the problem :]
sUriMatcher.addURI(BooksContract.CONTENT_AUTHORITY, BooksContract.PATH_BOOKS + "#/", BOOK_ID);
To query joins of table for cursorloader, i use ContentProvider at the bottom, however it is inside view pager and thus often recreates. This take considerable time to generate new table join.
Is it possible to create permanent join table, which will be automaticly updated its data, when source table get data update?
public class ContactsWithCategorisProvider extends ContentProvider {
private MySQLiteHelper database;
// used for the UriMacher
private static String TABLE_NAME = buildTableName();
private static String TABLE_ID = ContactsTable._ID;
private static String AUTHORITY = "app.ContactsWithCategorisProvider";
private static final int ITEMS = 10;
private static final int ITEM_ID = 20;
private static final String BASE_PATH = "app";
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
private static String buildTableName() {
StringBuilder sb = new StringBuilder();
sb.append(ContactsTable.TABLE_NAME);
sb.append(" LEFT OUTER JOIN ");
sb.append(ContactsCategoriesTable.TABLE_NAME);
sb.append(" ON(");
sb.append(ContactsCategoriesTable.CONTACT_ID);
sb.append(" = ");
sb.append(ContactsTable.CONTACT_ID);
sb.append(" AND ");
sb.append(ContactsCategoriesTable.CURRENT_USER);
sb.append(" = ");
sb.append(ContactsTable.CURRENT_USER);
sb.append(") ");
return sb.toString();
}
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH, ITEMS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH + "/#", ITEM_ID);
}
#Override public boolean onCreate() {
database = new MySQLiteHelper(getContext());
return true;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// Uisng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// check if the caller has requested a column which does not exists
// checkColumns(projection);
queryBuilder.setTables(TABLE_NAME);
if (projection == null || projection.length == 0) {
projection = new String[] {
ContactsTable.TABLE_NAME + "." + ContactsTable._ID + " AS " + ContactsTable._ID,
ContactsTable.NAME, ContactsTable.NAME_SHORT,ContactsTable.NUMBER, ContactsTable.NOTE,
ContactsTable.CATEGORIES, ContactsCategoriesTable.NAME, ContactsTable.CONTACT_ID,ContactsCategoriesTable.CATALOG_ID
};
}
if (TextUtils.isEmpty(sortOrder)) {
sortOrder =
ContactsCategoriesTable.NAME + " = 'UNSORTED' DESC, " + ContactsCategoriesTable.NAME
+ " ASC, " + ContactsTable.NAME + " ASC ";
}
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case ITEMS:
break;
case ITEM_ID:
// adding the _ID to the original query
queryBuilder.appendWhere(TABLE_ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor =
queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
// make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override public String getType(Uri uri) {
return null;
}
#Override public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
long id;
switch (uriType) {
case ITEMS:
id = sqlDB.insert(TABLE_NAME, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
public void insert(Uri uri, ArrayList<ContentValues> values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
switch (uriType) {
case ITEMS:
for (ContentValues c : values) {
sqlDB.insert(TABLE_NAME, null, c);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
}
#Override public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case ITEMS:
rowsDeleted = sqlDB.delete(TABLE_NAME, selection, selectionArgs);
break;
case ITEM_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(TABLE_NAME, TABLE_ID + "=" + id, null);
} else {
rowsDeleted =
sqlDB.delete(TABLE_NAME, TABLE_ID + "=" + id + " and " + selection, selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case ITEMS:
rowsUpdated = sqlDB.update(TABLE_NAME, values, selection, selectionArgs);
break;
case ITEM_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(TABLE_NAME, values, TABLE_ID + "=" + id, null);
} else {
rowsUpdated = sqlDB.update(TABLE_NAME, values, TABLE_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
}
I have a listview with some elements that are saved on a database and I access them using a custom content provider.
In my main activity, I have implemented a ResourceCursorAdapter.
When I long click on a element of the list, I get a context menu where I have the edit-update options.
The edit option starts other activity with some edittexts where I should be able to update the selected item's values (I use this activity too to create a new item, and I do this right).
The problem I'm getting is that I'm not getting the items updated nor deleted, so i think that I'm not mannaging right the ID to access the database. This is my code:
Custom Content Provider - Update and delete methods
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0;
database = mDbHelper.getWritableDatabase();
int match = mUriMatcher.match(uri);
switch (match){
case URI_TRAVELS:
//nada
break;
case URI_TRAVEL_ITEM:
String id = uri.getPathSegments().get(1);
count = database.update(TravelsDatabaseHelper.TABLE_NAME, values, Travels._ID +
" = " + id + (!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
database = mDbHelper.getWritableDatabase();
int match = mUriMatcher.match(uri);
switch (match){
case URI_TRAVELS:
//nada
break;
case URI_TRAVEL_ITEM:
String id = uri.getPathSegments().get(1);
count = database.delete(TravelsDatabaseHelper.TABLE_NAME, Travels._ID + " = " + id +
(!TextUtils.isEmpty(selection) ? " AND (" +
selection + ')' : ""), selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
Main Activity - Update and delete methods
public void updateTravel(String city, String country, int year, String note, String id){
ContentValues updateValues = new ContentValues();
updateValues.put(Travels.CITY, city);
updateValues.put(Travels.COUNTRY, country);
updateValues.put(Travels.YEAR, year);
updateValues.put(Travels.NOTE, note);
getContentResolver().update(TravelsProvider.CONTENT_URI, updateValues, Travels._ID+"="+id, null);
}
private void deleteTravel(String id){
/**Accede a la funcion delete() del Content Provider*/
getContentResolver().delete(TravelsProvider.CONTENT_URI, Travels._ID+"="+id, null);
}
Main Activity - Context menus where I call delete and update methods
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo menu_info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int itemPos = menu_info.position;
Cursor cursor = mAdapter.getCursor();
cursor.moveToPosition(itemPos);
switch (item.getItemId()) {
case R.id.edit_travel:
Intent intent = new Intent(this, EditTravelActivity.class);
intent.putExtra(TravelActivity.EXTRA_ID, cursor.getString(cursor.getColumnIndex(Travels._ID)));
startActivityForResult(intent, REQUEST_CODE_UPDATE_TRAVEL);
return true;
case R.id.delete_travel:
String ids = cursor.getString(cursor.getColumnIndex(Travels._ID));
deleteTravel(ids);
return true;
default:
return super.onContextItemSelected(item);
}
}
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
//...
case REQUEST_CODE_UPDATE_TRAVEL:
String ucity = data.getExtras().getString(TravelActivity.EXTRA_CITY);
String ucountry = data.getExtras().getString(TravelActivity.EXTRA_COUNTRY);
int uyear = data.getExtras().getInt(TravelActivity.EXTRA_YEAR);
String unote = data.getExtras().getString(TravelActivity.EXTRA_NOTE);
String uid = data.getExtras().getString(TravelActivity.EXTRA_ID);
updateTravel(ucity, ucountry, uyear, unote, uid);
break;
}
}
}
UPDATE - According to NigelK's answer
This is my "UriMatcher" and other relevant definitions to take care:
private static final String AUTHORITY = "com.example.travellist";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/travels");
private static final int URI_TRAVELS = 1;
private static final int URI_TRAVEL_ITEM = 2;
private static final UriMatcher mUriMatcher;
static {
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(AUTHORITY, "travels", URI_TRAVELS);
mUriMatcher.addURI(AUTHORITY, "travels/#", URI_TRAVEL_ITEM);
}
I don't need to do it in booth ways, I'm learning about this so just doing it in the best way is enough for me to learn.
According to your answer, I've tryed doing it the 2 ways:
private void deleteTravel(long id){
/*METHOD 1*/
getContentResolver().delete(TravelsProvider.CONTENT_URI, Travels._ID+"="+id, null);
/*METHOD 2*/
Uri uri = ContentUris.withAppendedId(TravelsProvider.CONTENT_URI, id);
getContentResolver().delete(uri, null, null);
}
public int delete(Uri uri, String selection, String[] selectionArgs) {
//...
switch (match){
case URI_TRAVELS:
//nada
break;
case URI_TRAVEL_ITEM:
/*METHOD 1*/
count = database.delete(TravelsDatabaseHelper.TABLE_NAME, selection, selectionArgs);
break;
/*METHOD 2*/
String rowId = uri.getPathSegments().get(1);
selection = Travels._ID +" = "+ rowId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
count = database.delete(TravelsDatabaseHelper.TABLE_NAME, selection, selectionArgs);
break;
//...
}
In the first way, it continues whithout deleting the item. In the second way, in the line of String rowId = uri.getPathSegments().get(1); throws me this error: Unreachable code!
Most Content Providers include a shortcut URI pattern that allows you to address a particular row by appending a row ID to the content URI. Where you do the following, you are providing the selection "WHERE _id = id", which is perfectly valid:
.delete(TravelsProvider.CONTENT_URI, Travels._ID+"="+id, null);
The uri above will be something like: content://com.package.provider/content
The short cut, which applies the action to just the id appended to the uri, is of the form:
uri = ContentUris.withAppendedId(TravelsProvider.CONTENT_URI, id);
.delete(uri, null, null);
The uri above will now be something like: content://com.package.provider/content/1234
The problem you have is that in your delete() and update() methods, you are trying to deal with the 2nd form, not the 1st (which is the URI form you're using in the call). Expand your uriMatcher to tell the difference, something like:
uriMatcher.addURI("your.package.provider", "content", URI_TRAVEL_ITEM);
uriMatcher.addURI("your.package.provider", "content/#", URI_TRAVEL_ITEM_ID);
In delete(), and similarly for update():
switch (match){
case URI_TRAVELS:
//nada
break;
case URI_TRAVEL_ITEM:
count = database.delete(TravelsDatabaseHelper.TABLE_NAME, selection, selectionArgs);
break;
case URI_TRAVEL_ITEM_ID:
String rowID = uri.getPathSegments().get(1);
selection = Travels._ID + "=" + rowID
+ (!TextUtils.isEmpty(selection) ?
" AND (" + selection + ')' : "");
count = database.delete(TravelsDatabaseHelper.TABLE_NAME, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
So where there is no id appended to the URI (it matches URI_TRAVEL_ITEM) it is a straightforward delete based upon the selection and arguments.
Where there is an id appended to the URI (it matches URI_TRAVEL_ITEM_ID), get the id from the URI using getPathSegments().get(1) and use the value to augment the selection passed in (so it applies to just that row) before doing the delete.
You've then got both types of URI covered and the rest of your code should (I hope) work.
Strange behaviour of SQLite update in ContentProvider.
Update method:
#Override
public int update(Uri uri, ContentValues updateValues, String whereClause, String[] whereValues) {
SQLiteDatabase db = TasksContentProvider.dbHelper.getWritableDatabase();
int updatedRowsCount;
String finalWhere;
db.beginTransaction();
// Perform the update based on the incoming URI's pattern
try {
switch (uriMatcher.match(uri)) {
case MATCHER_TASKS:
updatedRowsCount = db.update(TasksTable.TABLE_NAME, updateValues, whereClause, whereValues);
break;
case MATCHER_TASK:
String id = uri.getPathSegments().get(TasksTable.TASK_ID_PATH_POSITION);
finalWhere = TasksTable._ID + " = " + id;
// if we were passed a 'where' arg, add that to our 'finalWhere'
if (whereClause != null) {
finalWhere = finalWhere + " AND " + whereClause;
}
updatedRowsCount = db.update(TasksTable.TABLE_NAME, updateValues, finalWhere, whereValues);
break;
default:
// Incoming URI pattern is invalid: halt & catch fire.
throw new IllegalArgumentException("Unknown URI " + uri);
}
} finally {
db.endTransaction();
}
if (updatedRowsCount > 0) {
DVSApplication.getContext().getContentResolver().notifyChange(uri, null);
}
return updatedRowsCount;
}
Query method:
#Override
public Cursor query(Uri uri, String[] selectedColumns, String whereClause, String[] whereValues, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
// Choose the projection and adjust the "where" clause based on URI pattern-matching.
switch (uriMatcher.match(uri)) {
case MATCHER_TASKS:
qb.setTables(TasksTable.TABLE_NAME);
qb.setProjectionMap(tasksProjection);
break;
// asking for a single comic - use the rage comics projection, but add a where clause to only return the one
// comic
case MATCHER_TASK:
qb.setTables(TasksTable.TABLE_NAME);
qb.setProjectionMap(tasksProjection);
// Find the comic ID itself in the incoming URI
String taskId = uri.getPathSegments().get(TasksTable.TASK_ID_PATH_POSITION);
qb.appendWhere(TasksTable._ID + "=" + taskId);
break;
case MATCHER_TASK_COMMENTS:
qb.setTables(TaskCommentsTable.TABLE_NAME);
qb.setProjectionMap(taskCommentsProjection);
break;
case MATCHER_TASK_COMMENT:
qb.setTables(TaskCommentsTable.TABLE_NAME);
qb.setProjectionMap(taskCommentsProjection);
String commentId = uri.getPathSegments().get(TaskCommentsTable.TASK_COMMENT_ID_PATH_POSITION);
qb.appendWhere(TaskCommentsTable._ID + "=" + commentId);
break;
default:
// If the URI doesn't match any of the known patterns, throw an exception.
throw new IllegalArgumentException("Unknown URI " + uri);
}
SQLiteDatabase db = TasksContentProvider.dbHelper.getReadableDatabase();
// the two nulls here are 'grouping' and 'filtering by group'
Cursor cursor = qb.query(db, selectedColumns, whereClause, whereValues, null, null, sortOrder);
// Tell the Cursor about the URI to watch, so it knows when its source data changes
cursor.setNotificationUri(DVSApplication.getContext().getContentResolver(), uri);
return cursor;
}
Trying to update and row.
int affectedRowsCount = provider.update(Uri.parse(TasksTable.CONTENT_URI.toString() + "/"+ taskId), task.getContentValues(), null, null);
affectedRowsCount is eqaul to 1
Check if row is updated
Cursor cs = provider.query(TasksTable.CONTENT_URI, new String[] {TasksTable.TASK_STATE_VALUE}, TasksTable._ID +" = ?", new String[] {String.valueOf(taskId)}, null);
if(cs.moveToFirst()) {
String state = cs.getString(cs.getColumnIndex(TasksTable.TASK_STATE_VALUE));
}
state is the same as before update. Though update went succesful because affectedRowsCount is equal to 1 but selecting by the same id the same row seems that row wasn't updated at all.
In your update method you are using a transaction, but you never set the result as successful, so everytime you reach db.endTransaction() a rollback is performed. That's why your update isn't stored.
The changes will be rolled back if any transaction is ended without
being marked as clean (by calling setTransactionSuccessful). Otherwise
they will be committed.
You need to use
db.setTransactionSuccessful();
when your update is finished without errors. In your code, it should be after both your db.update.
Weird thing is my content provider doesn't delete the row I've asked to. As far as I see it should work and I don't understand why it doesn't.
This is the delete method in my provider:
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case SINGLE_ROW:
String rowID = uri.getPathSegments().get(1);
selection = KEY_ROWID
+ "="
+ rowID
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ')' : "");
Log.i("Selection", "" + selection);
break;
case ALLROWS:
Log.i("Deleted", "All rows");
break;
default:
Log.i("Switch case", "default value");
break;
}
if (selection == null) {
selection = "1";
}
int deleteCount = db.delete(helper.DATABASE_TABLE, selection,
selectionArgs);
Log.i("Deleted rows",
"" + db.delete(helper.DATABASE_TABLE, selection, selectionArgs));
getContext().getContentResolver().notifyChange(uri, null);
return deleteCount;
}
Here is the Log output which indicates no row was deleted which makes no sense to me.
can anyone help?
03-24 22:36:34.809: I/Selection(27648): _id=2
**03-24 22:36:34.809: I/Deleted rows(27648): 0**
03-24 22:36:34.814: I/Delete Uri(27648): content://com.shifts.provider/shiftsTEST/2
I've found the issue myself - I've refactored the method like this:
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int deleteCount = db.delete(helper.DATABASE_TABLE, KEY_ID + "="
+ Integer.valueOf(selection), null);
Log.i("Selection", "" + selection);
getContext().getContentResolver().notifyChange(uri, null);
return deleteCount;
}