Перейти к содержанию

Произвольные данные вставляются в ContentProvider

Описание

Если необходимо получить доступ к данным ContentProvider, используется объект ContentResolver. Он взаимодействует с объектом-поставщиком — экземпляром класса, который реализует ContentProvider. Объект ContentProvider получает запросы данных от клиентов, выполняет запрошенное действие и возвращает результаты. Методы ContentResolver предоставляют базовые функции «CRUD» (create, retrieve, update и delete) хранилища. Activity или Fragment вызывает CursorLoader для запроса, который, в свою очередь, получает ContentProvider с помощью ContentResolver.

// Запрашивает пользовательский словарик (UserDictionary) и возвращает результаты
cursor = contentResolver.query(
    UserDictionary.Words.CONTENT_URI,  // URI таблицы со словами
    projection,                        // Столбцы, которые вернутся для каждой строки
    selectionClause,                   // Selection условия
    selectionArgs.toTypedArray(),      // Selection параметры
    sortOrder                          // Порядок сортировки
)

Чтобы вставить данные в ContentProvider, необходимо вызвать метод ContentResolver.insert(). Этот метод вставляет новую строку в поставщик и возвращает URI контента для этой строки. В следующем фрагменте показано, как вставить новое слово в пользовательский словарь:

// Новый Uri объект, который получит результат вставки
Uri newUri;
...
// Объект, содержащий данные для вставки
ContentValues newValues = new ContentValues();

/*
 * Устанавливаем значения для каждой колонки и вставляем слова. Аргументы "put"
 * метода: "column name" и "value".
 */
newValues.put(UserDictionary.Words.APP_ID, "example.user");
newValues.put(UserDictionary.Words.LOCALE, "en_US");
newValues.put(UserDictionary.Words.WORD, "insert");
newValues.put(UserDictionary.Words.FREQUENCY, "100");

newUri = getContentResolver().insert(
    UserDictionary.Words.CONTENT_URI,   // UserDictionary content URI
    newValues                           // данные для вставки
);

Данные для новой строки помещаются в один объект ContentValues, который похож по форме на однострочный курсор. Столбцы в этом объекте не обязательно должны иметь один и тот же тип данных, более того, можно установить для столбца значение null с помощью ContentValues.putNull().

Предыдущий фрагмент не добавляет столбец _ID, поскольку этот столбец вычисляется автоматически. Поставщик присваивает уникальное значение _ID каждой добавляемой строке. Провайдеры обычно используют это значение в качестве первичного ключа таблицы.

URI содержимого, возвращаемый в newUri, идентифицирует вновь добавленную строку в следующем формате.

content://user_dictionary/words/<id_value>

<id_value> — это содержимое _ID для новой строки. Большинство провайдеров могут автоматически определять эту форму URI контента, а затем выполнять запрошенную операцию с этой конкретной строкой. Чтобы получить значение _ID из возвращенного Uri, вызовите ContentUris.parseId().

Важно

Вставка произвольных данных в ContentProvider может привести к серьезным проблемам с безопасностью или неожиданному поведению программы.

Рекомендации

  1. Защищайте Content Provider, если необходимо, чтобы провайдер был экспортируемым. Ограничивайте доступ к Content Provider с помощью атрибутов android:permission, android:readPermission или android:writePermission, или предоставляйте доступ только к конкретным uri с помощью <grant-uri-permission …/>, либо <path-permission.….

  2. Если у Content Provider есть атрибуты android:readPermission и android:writePermission одновременно, то не рекомендуется использовать одно и то же разрешение, чтобы, например, приложения, которым необходимо только чтение, не получали дополнительную возможность на запись и наоборот.

  3. Валидируйте данные, которые приходят в ContentValues в методе insert().

    Пример

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        String name = values.getAsString(PatientEntry.COLUMN_PATIENT_NAME);
        if (name == null || name.length()==0) {
            throw new IllegalArgumentException("Patient requires a name");
        }
    ...
    }
    

Ссылки

  1. ContentProvider basics
К началу