使用Content Provider更新数据库

时间:2014-01-15 09:38:50

标签: android sql cursor

我有一个listview,其中包含一些保存在数据库中的元素,我使用自定义内容提供程序访问它们。

在我的主要活动中,我实现了一个ResourceCursorAdapter。

当我长时间点击列表中的某个元素时,我会看到一个上下文菜单,其中包含编辑更新选项。

编辑选项通过一些edittexts启动其他活动,我可以在其中更新所选项目的值(我也使用此活动来创建新项目,我正确地执行此操作)。

我得到的问题是我没有更新或删除项目,所以我认为我没有正确的ID来访问数据库。这是我的代码:

自定义内容提供商 - 更新和删除方法

@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;
}

主要活动 - 更新和删除方法

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);
}

主要活动 - 我调用删除和更新方法的上下文菜单

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;
        }
    }
}

更新 - 根据NigelK的回答

这是我的“UriMatcher”和其他需要注意的相关定义:

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);
}

我不需要在展位上这样做,我正在了解这一点,所以只要以最好的方式做到这一点就足以让我学习。

根据你的回答,我尝试过两种方式:

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;
        //...
}

在第一种方式中,它会在没有删除项目的情况下继续。在第二种方式中,在 String rowId = uri.getPathSegments()。get(1); 的行中抛出了这个错误:无法访问的代码!

1 个答案:

答案 0 :(得分:2)

大多数内容提供商都包含一个快捷方式URI模式,允许您通过在内容URI中附加行ID来寻址特定行。如果您执行以下操作,则提供选项“WHERE _id = id”,这是完全有效的:

.delete(TravelsProvider.CONTENT_URI, Travels._ID+"="+id, null);

上面的uri将是:content://com.package.provider/content

快捷方式将操作应用于附加到uri的id,具有以下形式:

uri = ContentUris.withAppendedId(TravelsProvider.CONTENT_URI, id);
.delete(uri, null, null);

上面的uri现在将是:content://com.package.provider/content/1234

您遇到的问题是,在delete()和update()方法中,您正在尝试处理第二个表单,而不是第一个表单(这是您在调用中使用的URI表单)。扩展您的uriMatcher以区分,例如:

uriMatcher.addURI("your.package.provider", "content", URI_TRAVEL_ITEM);
uriMatcher.addURI("your.package.provider", "content/#", URI_TRAVEL_ITEM_ID);

在delete()中,类似于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);
}

因此,如果URI没有附加id(它与URI_TRAVEL_ITEM匹配),则根据选择和参数进行直接删除。 如果URI附加了一个id(它与URI_TRAVEL_ITEM_ID匹配),则使用getPathSegments()。get(1)从URI中获取id并使用该值来增加传入的选择(因此它仅适用于该行)做删除。

然后你已经覆盖了两种类型的URI,其余的代码应该(我希望)有效。