Content provider permissions android что это

Content provider (Контент-провайдер)

Что такое контент-провайдер

Контент-провайдер или «Поставщик содержимого» (Content Provider) — это оболочка (wrapper), в которую заключены данные. Если ваше приложение использует базу данных SQLite, то только ваше приложение имеет к ней доступ. Но бывают ситуации, когда данные желательно сделать общими. Простой пример — ваши контакты из телефонной книги тоже содержатся в базе данных, но вы хотите иметь доступ к данным, чтобы ваше приложение тоже могло выводить список контактов. Так как вы не имеете доступа к базе данных чужого приложения, был придуман специальный механизм, позволяющий делиться своими данными всем желающим.

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

В Android существует возможность выражения источников данных (или поставщиков данных) при помощи передачи состояния представления — REST, в виде абстракций, называемых поставщиками содержимого. Базу данных SQLite можно заключить в поставщик содержимого. Чтобы получить данные из поставщика содержимого или сохранить в нём новую информацию, нужно использовать набор REST-подобных идентификаторов URI. Например, если бы вам было нужно получить набор книг из поставщика содержимого, в котором заключена электронная библиотека, вам понадобился бы такой URI (по сути запрос к получению всех записей таблицы books):

Чтобы получить из библиотеки конкретную книгу (например, книгу №23), будет использоваться следующий URI (отдельный ряд таблицы):

Любая программа, работающая в устройстве, может использовать такие URI для доступа к данным и осуществления с ними определенных операций. Следовательно, поставщики содержимого играют важную роль при совместном использовании данных несколькими приложениями.

Встроенные поставщики

В Android используются встроенные поставщики содержимого (пакет android.provider). Вот неполный список поставщиков содержимого:

На верхних уровнях иерархии располагаются базы данных, на нижних — таблицы. Так, Browser, СаllLog, Contacts, MediaStore и Settings — это отдельные базы данных SQLite, инкапсулированные в форме поставщиков. Обычно такие базы данных SQLite имеют расширение DB и доступ к ним открыт только из специальных пакетов реализации (implerentation package). Любой доступ к базе данных из-за пределов этого пакета осуществляется через интерфейс поставщика содержимого.

Создание собственного контент-провайдера

Для создания собственного контент-провайдера нужно унаследоваться от абстрактного класса ContentProvider:

В классе необходимо реализовать абстрактные методы query(), insert(), update(), delete(), getType(), onCreate(). Прослеживается некоторое сходство с созданием обычной базы данных.

А также его следует зарегистрировать в манифесте с помощью тега provider с атрибутами name и authorities. Тег authorities служит для описания базового пути URI, по которому ContentResolver может найти базу данных для взаимодействия. Данный тег должен быть уникальным, поэтому рекомендуется использовать имя вашего пакета, чтобы не произошло путаницы с другими приложениями, например:

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

Итак, поставщики содержимого, как и веб-сайты, имеют базовое доменное имя, действующее как стартовая URL-страница.

Необходимо отметить, что поставщики содержимого, используемые в Android, могут иметь неполное имя источника. Полное имя источника рекомендуется использовать только со сторонними поставщиками содержимого. Поэтому вам иногда могут встретиться поставщики содержимого, состоящие из одного слова, например contacts, в то время как полное имя такого поставщика содержимого — com.google.android.contacts.

В поставщиках содержимого также встречаются REST-подобные гиперссылки, предназначенные для поиска данных и работы с ними. В случае описанной выше регистрации унифицированный идентификатор ресурса, предназначенный для обозначения каталога или коллекции записей в базе данных NotePadProvider, будет иметь имя:

Читайте также:  Андроид для bmw f20

URI для идентификации отдельно взятой записи будет иметь вид:

Символ # соответствует конкретной записи (ряд таблицы). Ниже приведено еще несколько примеров URI, которые могут присутствовать в поставщиках содержимого:

Обратите внимание — здесь поставщики содержимого content://media и content://contacts имеют неполную структуру. Это обусловлено тем, что данные поставщики содержимого не являются сторонними и контролируются Android.

Структура унифицированных идентификаторов содержимого (Content URI)

Для получения данных из поставщика содержимого нужно просто активировать URI. Однако при работе с поставщиком содержимого найденные таким образом данные представлены как набор строк и столбцов и образуют объект Android cursor. Рассмотрим структуру URI, которую можно использовать для получения данных.

Унифицированные идентификаторы содержимого (Content URI) в Android напоминают HTTP URI, но начинаются с content и строятся по следующему образцу:

Вот пример URI, при помощи которого в базе данных идентифицируется запись, имеющая номер 23:

После content: в URI содержится унифицированный идентификатор источника, который используется для нахождения поставщика содержимого в соответствующем реестре. Часть URI ru.alexanderklimov.provider.notepad представляет собой источник.

/notes/23 — это раздел пути (path section), специфичный для каждого отдельного поставщика содержимого. Фрагменты notes и 23 раздела пути называются сегментами пути (path segments). Одной из функций поставщика содержимого является документирование и интерпретация раздела и сегментов пути, содержащихся в URI.

UriMatcher

Провайдер имеет специальный объект класса UriMatcher, который получает данные снаружи и на основе полученной информации создаёт нужный запрос к базе данных.

Вам нужно задать специальные константы, по которым провайдер будет понимать дальнейшие действия. Если используется одна таблица, то обычно применяют две константы — любые два целых числа, например, 100 для таблицы и 101 для отдельного ряда таблицы. Схематично можно изобразить так.

URI pattern Code Contant name
content://ru.alexanderklimov.provider.notepad/notes 100 NOTES
content://ru.alexanderklimov.provider.notepad/notes/# 101 NOTES_ID

В коде с помощью switch создаётся ветвление — хотим ли мы получить информацию о всей таблице (код 100) или к конкретному ряду (код 101).

Приложение может быть сложным и иметь несколько таблиц. Тогда и констант будет больше. Например, так.

URI pattern Code Contant name
content://com.android.contacts/contacts 1000 CONTACTS
content://com.android.contacts/contacts/# 1001 CONTACTS_ID
content://com.android.contacts/lookup/* 1002 CONTACTS_LOOKUP
content://com.android.contacts/lookup/*/# 1003 CONTACTS_LOOKUP_ID
. . .
content://com.android.contacts/data 3000 DATA
content://com.android.contacts/data/# 3001 DATA_ID
. . .

Символ решётки (#) отвечает за число, а символ звёздочки (*) за строку.

Метод query()

Метод query() является обязательным для класса ContentProvider. Если мы используем контент-провайдер для обращения к базе данных, то в нём вызывает одноимённый метод SQLiteDatabase. Состав метода практически идентичен.

Вам нужно программно получить необходимые данные для аргументов метода. Обратите внимание на метод ContentUris.parseId(uri), который возвращает последний сегмент адреса, в нашем случае число 3, для Selection Args.

Метод insert()

Метод insert() содержит два параметра — URI и ContenValues. Первый параметр работает аналогично, как в методе query(). Вторая вставляет данные в нужные колонки таблицы.

Для вставки используется вспомогательный метод insertGuest().

Структурирование МIМЕ-типов в Android

Как веб-сайт возвращает тип MIME для заданной гиперссылки (это позволяет браузеру активировать программу, предназначенную для просмотра того или иного типа контента), так и в поставщике содержимого предусмотрена возможность возвращения типа MIME для заданного URI. Благодаря этому достигается определенная гибкость при просмотре данных. Если мы знаем, данные какого именно типа получим, то можем выбрать одну или несколько программ, предназначенных для представления таких данных. Например, если на жестком диске компьютера есть текстовый файл, мы можем выбрать несколько редакторов, которые способны его отобразить.

Типы MIME работают в Android почти так же, как и в НТТР. Вы запрашиваете у контент-провайдера тип MIME определенного поддерживаемого им URI, и поставщик содержимого возвращает двухчастную последовательность символов, идентифицирующую тип MIME в соответствии с принятыми стандартами.

Обозначение MIME состоит из двух частей: типа и подтипа. Ниже приведены примеры некоторых известных пар типов и подтипов MIME:

Читайте также:  Айклауд вход с андроида облако

text/html
text/css
text/xml
image/jpeg
audio/mp3
video/mp4
application/pdf
application/msword

Основные зарегистрированные типы содержимого:

application
audio
image
message
model
multipart
text
video

В Android применяется схожий принцип для определения типов MIME. Обозначение vnd в типах MIME в Android означает, что данные типы и подтипы являются нестандартными, зависящими от производителя. Для обеспечения уникальности в Android типы и подтипы разграничиваются при помощи нескольких компонентов, как и доменные имена. Кроме того, типы MIME в Android, соответствующие каждому типу содержимого, существуют в двух формах: для одиночной записи и для нескольких записей.

Типы MIME широко используются в Android, в частности при работе с намерениями, когда система определяет по МIМЕ-типу данных, какое именно явление следует активировать. Типы MIME всегда воспроизводятся контент-провайдерами на основании соответствующих URI. Работая с типами MIME, необходимо не упускать из виду три аспекта.

  1. Тип и подтип должны быть уникальными для того типа содержимого, который они представляют. Обычно это каталог с элементами или отдельный элемент. В контексте Android разница между каталогом и элементом может быть не такой очевидной, как кажется на первый взгляд.
  2. Если тип или подтип не являются стандартными, им должен предшествовать префикс vnd (обычно это касается конкретных видов записи).
  3. Обычно типы и подтипы относятся к определенному пространству имен в соответствии с вашими нуждами.

Необходимо еще раз подчеркнуть этот момент: основной тип MIME для коллекции элементов, возвращаемый командой cursor в Android, всегда должен иметь вид vnd.android.cursor.dir, а основной тип MIME для одиночного элемента, находимый командой cursor в Android, — вид vnd.android.cursor.item. Если речь идет о подтипе, то поле для маневра расширяется, как в случае с vnd.googlе.note; после компонента vnd. вы можете свободно выбирать любой устраивающий вас подтип.

ContentResolver

Каждый объект Content, принадлежащий приложению, включает в себя экземпляр класса ContentResolver, который можно получить через метод getContentResolver().

ContentResolver используется для выполнения запросов и транзакций от активности к контент-провайдеру. ContentResolver включает в себя методы для запросов и транзакций, аналогичные тем, что содержит ContentProvider. Объекту ContentResolver не нужно знать о реализации контент-провайдера, с которым он взаимодействует — любой запрос всего лишь принимают путь URI, в котором указано, к какому объекту ContentProvider необходимо обращаться.

Источник

ziginsider

18 августа 2017

ContentProvider – это класс, предоставляющий унифицированный интерфейс для доступа к данным приложения. Этот класс позволяет вам использовать единый источник данных в вашем приложении.

Задуман, как способ предоставлять данные вашего приложения для сторонних приложений, + для реализации поиска среди данных вашего приложения с использованием search suggestions (подсказки при вводе слов для поиска).

На практике часто используется для создания единого источника данных внутри приложения (В противовес заявлению в оф.докумментации: “You don’t need to develop your own provider if you don’t intend to share your data with other applications.”). При этом получаем связки: ContentProvider & SQLite, ContentProvider & CursorLoader, ContentProvider & Loader…

В пользу только лишь внутреннего использования (польза для внешнего очевидна) ContentProvider’a говорит следующее:

Как уже было сказано, ContentProvider предоставляет унифицированный интерфейс для доступа к данным. Это говорит о том, что не нужно беспокоится о реализации хранения данных. Она может меняться, но данные остаются доступны.

Не нужно управлять жизненным циклом объекта для доступа к данным (к примеру, экземпляра SQLiteDatabase). Ведь в случае прямого использования таких объектов возникает немало вопросов: где хранить этот объект? Когда закрывать базу данных? Когда уничтожать этот объект? ContentProvider позволяет получать доступ к данным из любого места, где доступен контекст приложения (экземпляр Context).

ContentProvider полностью соответствует концепциям REST (о которых мы говорили в этих заметках)

Немного о последнем пункте. Итак, соответствие REST:

  • Для каждой сущности ContentProvider’a есть свой URI.
  • Регистрация в манифесте ContentProvider’a выглядит следующим образом (пока без пояснения и др. возможных атрибутов):
  • рекомендуется использовать в качестве authority имя пакета с префиксом поясняющим суть провайдера, например для нашего списка контактов можно было бы применить: io.github.ziginsider.peopleprovider
  • URI образуется по схеме:
  • У ContentProvider’a приложения всегда определен базовый URI. Он складывается из префикса “content://” и authorities. Таким образом, для нашего примера базовый URI = “content://io.github.ziginsider.peopleprovider”
  • Далее, допустим мы хотим создать группу, в которой будет храниться информация о писателях (в рамках базы данных это будет таблица). Тогда URI для этой группы должно выглядеть следующим образом: “content://io.github.ziginsider.peopleprovider/writers”. Если мы обратимся к данным в ContentProvider по этому URI, то получим все экземпляры, сохраненные в этой группе.
  • И наконец, если нам нужно URI для отдельного объекта, то оно будет выглядеть следующим образом: “content://io.github.ziginsider.peopleprovider/writers/4”. Где 4 – это номер добавленного экземпляра.
Читайте также:  Zte blade mozilla android

Создание своего СontentProvider’a

На практике нам необходимо наследоваться от класса ContentProvider и реализовать следующие методы:

  • инициализирует ContentProvider. Провайдер будет создан как только вы обратитесь к нему с помощью ContentResolver’a. Возвращает true, если ContentProvider создан успешно. В общем случае, не рекомендуется делать в onCreate() ContentProvider’a длительных операций т.к. это может повесить onCreate() Application (??)
  • Возвращает объект Cursor по полученному URI. URI парсится, согласно заданным нами правилам. В случае использования в качестве источника данных БД SQLite извлекает данные из БД, и возвращает их в виде Cursor. (соответствует HTTP методу GET).
  • добавляет новые данные, возвращает URI новой записи. (соответствует HTTP методу POST)
  • добавляет массив элементов (не является обязательным для реализации в отличии от всех остальных методов)
  • обновляет строки в хранилище данных согласно заданным условиям. (в терминологии HTTP методов – PUT или PATCH)
  • удаляет данные. ( единственный метод ContentProvider, HTTP аналог которого имеет такое же название)
  • возвращает MIME-тип для заданной content URI. Обычно этот метод используют для сопоставления имени таблицы и URI, чтобы потом выполнить запрос к базе данных.

Следует помнить, что все перечисленные методы кроме onCreate() могут выполняться одновременно в нескольких потоках, и поэтому должны быть потоко-безопасными (thread-safe).

Допустим, мы создали свой ContentProvider, добавили его в манифесте и теперь можем обращаться к нему в качестве интерфейса для работы с данными. Но здесь есть небольшая тонкость – мы создавали объект ContentProvider, но обращаться к данным нужно через объект ContentResolver, который можно получить через метод getContentResolver в классе Context:

Манифест

Регистрация ContentProvider’a в манифесте под тегом

Атрибут android:exporter задает возможность использования нашего ContentProvider’a сторонними приложениями. До версии Android 16 по умолчанию был true, в версиях >= 16 по умолчанию false. Поэтому необходимо обращать внимание на состояние этого атрибута.

Атрибут android:authorities задает ключ по которому мы будем обращаться к нашему ContentProvider’у. Стоит обратить внимание на его уникальность. Установка приложений с одним и тем же значением authorities на одно устройство выдаст ошибку.

Атрибуты android:permission, android:readPermission, android:writePermission — задают ограничения на использование нашего ContentProvider’a сторонними приложениями (на доступ к ContentProvider’у внутри нашего приложения эти атрибуты не влияют). Атрибут android:readPermission и android:writePermission имеют приоритет над атрибутом android:permission, и, соответственно, отвечают за доступ к функции query() и фунциям insert(), bulkInsert(), update(), delete() нашего ContentProvider’a для стороннего приложения.

Например, в манифесте записано следующее:

Тогда в манифесте стороннего приложения, которое должно иметь доступ на чтение данных из ContentProvider’a должно быть указано разрешение:

Формирование URI

Соответсвие ContentProvider’a концепции REST выражается в том, что доступ к данным осуществляется с помощью URI. Соответственно, URI необходимо как-то формировать для запроса к необходимым данным.

URI — (Uniform Resource Identifier) унифицированный (единообразный) идентификатор ресурса. По-сути, символьная строка, позволяющая идентифицировать какой-либо ресурс.

Мы уже говорили, что URI ContentProvider’a формируется по следующей схеме:

Проверяем на соответствие в операторе Switch:

Источник

Оцените статью