Схема URI Android ContentProvider для уведомления CursorAdapters, прослушивающих запросы OUTER JOIN

У меня есть Android ContentProvider, который позволяет делать запросы LEFT OUTER JOIN в базе данных SQLite.

Предположим, что в базе данных есть 3 таблицы, Users, Articles и Comments. ContentProvider выглядит следующим образом:

public class SampleContentProvider extends ContentProvider {
    private static final UriMatcher sUriMatcher;
    public static final String AUTHORITY = "com.sample.contentprovider";
    private static final int USERS_TABLE = 1;
    private static final int USERS_TABLE_ID = 2;
    private static final int ARTICLES_TABLE = 3;
    private static final int ARTICLES_TABLE_ID = 4;
    private static final int COMMENTS_TABLE = 5;
    private static final int COMMENTS_TABLE_ID = 6;
    private static final int ARTICLES_USERS_JOIN_TABLE = 7;
    private static final int COMMENTS_USERS_JOIN_TABLE = 8;

    // [...] other ContentProvider methods

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        String table = getTableName(uri);

        // SQLiteWrapper is a wrapper class to manage a SQLiteHelper
        Cursor c = SQLiteWrapper.get(getContext()).getHelper().getReadableDatabase()
                .query(table, projection, selection, selectionArgs, null, null, sortOrder);

        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        String table = getTableName(uri);

        // SQLiteWrapper is a wrapper class to manage a SQLiteHelper
        long id = SQLiteWrapper.get(getContext()).getHelper().getWritableDatabase()
                .insert(table, null, values);

        Uri itemUri = ContentUris.withAppendedId(uri, id);
        getContext().getContentResolver().notifyChange(itemUri, null);

        return itemUri;
    }

    private String getTableName(Uri uri) {
        switch (sUriMatcher.match(uri)) {
        case USERS_TABLE:
        case USERS_TABLE_ID:
            return "Users";

        case ARTICLES_TABLE:
        case ARTICLES_TABLE_ID:
            return "Articles";

        case COMMENTS_TABLE:
        case COMMENTS_TABLE_ID:
            return "Comments";

        case ARTICLES_USERS_JOIN_TABLE:
            return "Articles a LEFT OUTER JOIN Users u ON (u._id = a.user_id)";

        case COMMENTS_USERS_JOIN_TABLE:
            return "Comments c LEFT OUTER JOIN Users u ON (u._id = c.user_id)";

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

    static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(AUTHORITY, "users", USERS_TABLE);
        sUriMatcher.addURI(AUTHORITY, "articles", ARTICLES_TABLE);
        sUriMatcher.addURI(AUTHORITY, "comments", COMMENTS_TABLE);
        sUriMatcher.addURI(AUTHORITY, "users" + "/#", USERS_TABLE_ID);
        sUriMatcher.addURI(AUTHORITY, "articles" + "/#", ARTICLES_TABLE_ID);
        sUriMatcher.addURI(AUTHORITY, "comments" + "/#", COMMENTS_TABLE_ID);
        sUriMatcher.addURI(AUTHORITY, "???", ARTICLES_USERS_JOIN_TABLE); // what uri here?
        sUriMatcher.addURI(AUTHORITY, "???", COMMENTS_USERS_JOIN_TABLE); // what uri here?
    }
}

Какая лучшая схема URI уведомляет все CursorAdapter прослушивание подключенных и несвязанных запросов каждый раз, когда я вставляю (или обновляю) строку в таблице Users?

Другими словами, если я добавляю или обновляю новую строку в одной из таблиц, я хочу отправить уведомление одиночное с помощью getContext().getContentResolver().notifyChange(itemUri, null), чтобы все CursorAdapter прослушивали любой запрос (USERS_TABLE, ARTICLES_USERS_JOIN_TABLE, COMMENTS_USERS_JOIN_TABLE) получают уведомление об обновлении своего контента.

Если это невозможно, есть ли альтернативный способ оповестить всех наблюдателей?

Ответ 1

У вас может быть специальный Uri для запроса:

    sUriMatcher.addURI(AUTHORITY, "articlesusers", ARTICLES_USERS_JOIN_TABLE);
    sUriMatcher.addURI(AUTHORITY, "commentsusers", COMMENTS_USERS_JOIN_TABLE);

Но я не могу придумать способ отправить одно уведомление. Кажется, ваш лучший выбор - отправить уведомление для каждого Uri, относящегося к изменяемой таблице. Таким образом, ваши методы вставки/обновления/удаления вызовут notifyChange несколько раз в зависимости от затронутой таблицы. Для внесения изменений в "пользователей" было бы 3 уведомления - пользователи, статьи и пользователи комментариев, поскольку все они зависят от таблицы "users".

Ответ 2

Как указано prodaea, вот еще одна альтернатива, которую вы можете использовать для уведомления Uri. Это не идеальное решение, но для уведомления используется только один Uri.

Решение состоит в том, чтобы использовать основной Uri без имени таблицы (например: content://com.example.app.provider/) в качестве уведомления Uri в методе запроса для ARTICLES_USERS_JOIN_TABLE и COMMENTS_USERS_JOIN_TABLE. Таким образом, связанный курсор будет уведомлен о каждом изменении таблицы. Однако есть одно ограничение. То есть, ARTICLES_USERS_JOIN_TABLE курсор будет уведомлен, даже если в таблице Articles есть изменения.

Для таблиц Users' and Articles 'вы можете использовать свой специальный Uris для уведомления.