Android java content provider

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

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

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

  • AlarmClock : управление будильником
  • Browser : история браузера и закладки
  • CalendarContract : каледарь и информаци о событиях
  • CallLog : информация о звонках
  • ContactsContract : контакты
  • MediaStore : медиа-файлы
  • SearchRecentSuggestions : подсказки по поиску
  • Settings : системные настройки
  • UserDictionary : словарь слов, которые используются для быстрого набора
  • VoicemailContract : записи голосовой почты

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

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

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

ArrayList contacts = new ArrayList(); ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if(cursor!=null) < while (cursor.moveToNext()) < // получаем каждый контакт String contact = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)); // добавляем контакт в список contacts.add(contact); >cursor.close(); >

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

Читайте также:  Запретить html теги php

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

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

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

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

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

package com.example.contactsapp; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.ContentResolver; import android.content.pm.PackageManager; import android.database.Cursor; import android.os.Bundle; import android.provider.ContactsContract; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends AppCompatActivity < private static final int REQUEST_CODE_READ_CONTACTS=1; private static boolean READ_CONTACTS_GRANTED =false; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // получаем разрешения int hasReadContactPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS); // если устройство до API 23, устанавливаем разрешение if(hasReadContactPermission == PackageManager.PERMISSION_GRANTED)< READ_CONTACTS_GRANTED = true; >else< // вызываем диалоговое окно для установки разрешений ActivityCompat.requestPermissions(this, new String[], REQUEST_CODE_READ_CONTACTS); > // если разрешение установлено, загружаем контакты if (READ_CONTACTS_GRANTED) < loadContacts(); >> @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) < super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_READ_CONTACTS) < if (grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) < READ_CONTACTS_GRANTED = true; >> if(READ_CONTACTS_GRANTED) < loadContacts(); >else < Toast.makeText(this, "Требуется установить разрешения", Toast.LENGTH_LONG).show(); >> private void loadContacts() < ContentResolver contentResolver = getContentResolver(); Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); ArrayListcontacts = new ArrayList(); if(cursor!=null) < while (cursor.moveToNext()) < // получаем каждый контакт String contact = cursor.getString( cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)); // добавляем контакт в список contacts.add(contact); >cursor.close(); > // создаем адаптер ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, contacts); ListView contactList = findViewById(R.id.contactList); // устанавливаем для списка адаптер contactList.setAdapter(adapter); > >

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

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

int hasReadContactPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS); if(hasReadContactPermission == PackageManager.PERMISSION_GRANTED)

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

ActivityCompat.requestPermissions(this, new String[], REQUEST_CODE_READ_CONTACTS);

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

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

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

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

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) < super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_READ_CONTACTS) < if (grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) < READ_CONTACTS_GRANTED = true; >> if(READ_CONTACTS_GRANTED) < loadContacts(); >else < Toast.makeText(this, "Требуется установить разрешения", Toast.LENGTH_LONG).show(); >>

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

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

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

Чтение контактов в Android

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

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

Источник

Поставщики содержимого. Взаимодействие с контактами

image

Доброго времени суток, уважаемые Хабровчане!

Как все вы знаете — Android это потенциально развивающаяся и конкуретноспособная операционная система. Разработчиков под эту систему с каждым днем ставновится все больше и больше. Хоть я и начинающий разработчик под Android, я не буду рассказывать вам, как установить Eclipse и ADT под него.

В этом топике я хотел бы рассказать о поставщиках содержимого в операционной системе Android и привести небольшой пример работы с одним из них.

Что такое поставщики содержимого

Поставщики содержимого (content providers) — сущности предназначенные для обобщения данных в службах. Благодаря применению поставщиков содержимого источники данных становятся похожи на оснащенные функциями передачи состояния представления (REST) поставщики данных

Что такое REST

REST (Representational state transfer) – это стиль архитектуры программного обеспечения для распределенных систем, таких как World Wide Web, который, как правило, используется для построения веб-служб. Термин REST был введен в 2000 году Роем Филдингом, одним из авторов HTTP-протокола. Системы, поддерживающие REST, называются RESTful-системами.

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

А теперь тоже самое более наглядно:

Отсутствие дополнительных внутренних прослоек означает передачу данных в том же виде, что и сами данные. Т.е. мы не заворачиваем данные в XML, как это делает SOAP и XML-RPC, не используем AMF, как это делает Flash и т.д. Просто отдаем сами данные.

Каждая единица информации однозначно определяется URL – это значит, что URL по сути является первичным ключом для единицы данных. Т.е. например третья книга с книжной полки будет иметь вид /book/3, а 35 страница в этой книге — /book/3/page/35. Отсюда и получается строго заданный формат. Причем совершенно не имеет значения, в каком формате находятся данные по адресу /book/3/page/35 – это может быть и HTML, и отсканированная копия в виде jpeg-файла, и документ Microsoft Word.

Как происходит управление информацией сервиса – это целиком и полностью основывается на протоколе передачи данных. Наиболее распространенный протокол конечно же HTTP. Так вот, для HTTP действие над данными задается с помощью методов: GET (получить), PUT (добавить, заменить), POST (добавить, изменить, удалить), DELETE (удалить). Таким образом, действия CRUD (Create-Read-Update-Delete) могут выполняться как со всеми 4-мя методами, так и только с помощью GET и POST.

Вот как это будет выглядеть на примере:

GET /book/ — получить список всех книг
GET /book/3/ — получить книгу номер 3
PUT /book/ — добавить книгу (данные в теле запроса)
POST /book/3 – изменить книгу (данные в теле запроса)
DELETE /book/3 – удалить книгу

Виды стандартных поставщиков содержимого в Android
- Browser - CallLog - Contacts - People - Phones - Photos - Groups - MediaStore - Audio - Albums - Artists - Genres - Playlists - Images - Thumbnails - Video - Settings

На верхних уровнях иерархии распологаются базы данных SQLite, на нижних — таблицы. Следовательно — Browser, CallLog, Contacts, MediaStore, Settings — это отдельные базы данных SQLite, инкапсулированные в форме поставщиков.

Архитектура поставщиков содержимого

Каждый поставщик содержимого регистрируется в устройстве как веб-сайт, при помощи специальной строки (она похожа на доменное имя и называется authority). Такая уникальная последовательность набора символов в устройстве представляет собой основу для набора URI.

Регистрация источника осуществляется в файле AndroidManifest.xml. Ниже приведено два примера, как можно регистрировать поставщиков содержимого в Android.

content://com.google.provider.NotePad/notes/ — получение всех записей
content://com.google.provider.NotePad/notes/# — получение одной записи по ID

Ниже приведено еще несколько URI для поставщиков содержимого

content://media/internal/images/
content://media/external/images/
content://contacts/people/
content://contacts/people/23

Здесь поставщики (content://media/) и (content://contacts) имеют не полную структуру, это означает, что данные поставщики содержимого не являются сторонними и контролируются системой Android.

Рассмотрим конкретный URI более детально:

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

В данном URI часть com.google.provider.NotePad представляет собой источник.
/notes/23 — это раздел пути (path section), специфичный для каждого отдельного поставщика содержимого

Считывание данных контактов при помощи URI

Важно помнить о системе безопасности в Android, поэтому в файл AndroidManifest.xml добавим:

Более подробно о правах доступа можно почитать тут

Эквивалентная текстовая URI строка будет иметь вид:

При использовании таких URI код для получения строк будет иметь следующий вид:

/* Создаем новый управляемый курсор */ Cursor managedCursor = managedQuery(People.CONTENT_URI, new String[] < People._ID, People.NAME, People.NUMBER >, // Какие колонки возвращать null, // Какие строки возвращать(все) null, // Выбор аргументов People.NAME + " ASC"); // Метод сортировки // Начинаем управлять курсором: startManagingCursor(managedCursor); // Проверяем, есть ли в курсоре строки if (managedCursor.getCount() > 0) < while (managedCursor.moveToNext()) < // Посылаем сообщение в дебагер Log.i("DATA", managedCursor.getString(0) + " :: " // Полученное значение _ID + managedCursor.getString(1) + " " // Полученное значение NAME + managedCursor.getString(2)); // Полученное значение NUMBER >> 

Источник

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