Контент провайдер это 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, будет иметь имя:

Читайте также:  Что такое рекавери меню для андроид

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. Благодаря этому достигается определенная гибкость при просмотре данных. Если мы знаем, данные какого именно типа получим, то можем выбрать одну или несколько программ, предназначенных для представления таких данных. Например, если на жестком диске компьютера есть текстовый файл, мы можем выбрать несколько редакторов, которые способны его отобразить.

Читайте также:  Режим чтения android для чего

Типы 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 необходимо обращаться.

Источник

Провайдеры контента

Наше приложение может сохранять разнообразую информацию о пользователе, какие-то связанные данные в файлах или настройках. Однако ОС Android уже хранит ряд важной информации, связанной с пользователем, к которой имеем доступ и которую мы можем использовать. Это и списки контактов, и файлы сохраненных изображений и видеоматериалов, и какие-то отметки о звонках и т.д., то есть некоторый контент. А для доступа к этому контенту в OC Android определены провайдеры контента (content provider)

В Android имеются следующие встроенные провайдеры, определенные в пакете android.content :

AlarmClock : управление будильником

Browser : история браузера и закладки

CalendarContract : каледарь и информаци о событиях

CallLog : информация о звонках

SearchRecentSuggestions : подсказки по поиску

Settings : системные настройки

UserDictionary : словарь слов, которые используются для быстрого набора

VoicemailContract : записи голосовой почты

Работа с контактами

Контакты в Android обладают встроенным API, который позволяет получать и изменять список контактов. Все контакты хранятся в базе данных SQLite, однако они не представляют единой таблицы. Для контактов отведено три таблицы, связанных отношением один-ко-многим: таблица для хранения информации о людях, таблица их телефонов и и таблица адресов их электронных почт. Но благодаря Android API мы можем абстрагироваться от связей между таблицами.

Читайте также:  Android смартфон за 6000

Общая форма получения контактов выглядит следующим образом:

Все контакты и сопутствующий функционал хранятся в специальных базах данных SQLite. Но нам не надо напрямую работать с ними. Мы можем воспользоваться объектом класса Cursor . Чтобы его получить, сначала вызывается метод getContentResolver() , который возвращает объект ContentResolver . Затем по цепочке вызывается метод query() . В этот метод передается ряд параметров, первый из которых представляет URI — ресурс, который мы хотим получить. Для обращения к базе данных контактов используется константа ContactsContract.Contacts.CONTENT_URI

Метод contactsCursor.moveToNext() позволяет последовательно перемещаться по записям контактов, считывая по одному контакту через вызов contactsCursor.getString() .

Таким образом, получать контакты не сложно. Главная сложность в работе с контактами, да и с любыми другими провайдерами контента, заключается в установке разрешений. До Android API 23 достаточно было установить соответствующее разрешение в файле манифеста приложения. Начиная же с API 23 (Android Marshmallow) Google изменил схему работы с разрешениями. И теперь пользователь сам должен решить, будет ли он давать разрешения приложению. В связи с чем разработчики должны добавлять дополнительный код.

Итак, для доступа к контактам нам надо установить разрешение android.permission.READ_CONTACTS в файле манифеста приложения:

Для вывода списка контактов в файле activity_main.xml определим следующую разметку интерфейса:

Для вывода списка контактов воспользуемся элементом ListView. И в классе MainActivity получим контакты:

Кроме собственно загрузки контактов и передачи их через адаптер ArrayAdapter в список ListView здесь добавлено много кода по управлению разрешениями. Вначале определена переменная READ_CONTACTS_GRANTED , которая указывает, было ли выдано разрешение. И здеь есть два варианта действий.

Первый вариант предполагает, что устройство имеет версию Android ниже Marshmallow (ниже API 23). Для этого мы просто узнаем, есть ли разрешение для READ_CONTACTS и если оно есть, то устанавливаем для переменной READ_CONTACTS_GRANTED значение true :

Иначе нам надо отобразить пользователю диалоговое окно, где он решить, надо ли дать приложению разрешение:

В этот метод передаются три параметра. Первый — текущий контекст, то есть текущий объект Activity.

Второй параметр представляет набор разрешений, которые надо получить, в виде массива строк. Нам надо получить в данном случае только одно разрешение — Manifest.permission.READ_CONTACTS.

Третий параметр представляет код запроса, через который мы сможем получить ответ пользователя.

Если мы хотим получить выбор пользователя при установке разрешений, то нам надо переопределить в классе Activity метод onRequestPermissionsResult :

Первый параметр метода requestCode — это тот код запроса, который передавался в качестве третьего параметра в ActivityCompat.requestPermissions() . Второй параметр — массив строк, для которых устанавливались разрешения. То есть одномоментно мы можем устанавливать сразу несколько разрешений.

Третий параметр собственно хранит числовые коды разрешений. Так мы запрашиваем только одно разрешение, то первый элемент массива будет хранить его код. Через условное выражение мы можем проверить этот код: grantResults[0] == PackageManager.PERMISSION_GRANTED . И в зависимости от результата проверки изменить переменную READ_CONTACTS_GRANTED.

И при запуске приложения нам сначала отобразится окно для выдачи разрешения, а после выдачи подтверждений список контактов:

После выдачи разрешения при повторных запусках приложения повторять разрешение не нужно, поэтому метод onRequestPermissionsResult() в таком случае будет срабатывать только один раз. А переменная READ_CONTACTS_GRANTED в этом случае уже будет иметь значение true.

Другоая ситуация — если мы отклоним разрешение. В этом случае при повторном запуске приложения повторно будет отображаться данное окно.

Источник

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