моб разраб. Лабораторные работы с 1 по 21. Лабораторная работа Использование значений строк и цветов
Скачать 5.49 Mb.
|
Контент-провайдерыКонтент-провайдеры предоставляют интерфейс для публикации и потребления структурированных наборов данных, основанный на URI с использованием простой схемы content://. Их использование позволяет отделить код приложения от данных, делая программу менее чувствительной к изменениям в источниках данных. Для взаимодействия с контент-провайдером используется уникальный URI, который обычно формируется следующим образом: content://<домен-разработчика-наоборот>.provider.<имя-приложения>/<путь-к-даным> Классы, реализующие контент-провайдеры, чаще всего имеют статическую строковую константу CONTENT_URI, которая используется для обращения к данному контент- провайдеру. Контент-провайдеры являются единственным способом доступа к данным других приложений и используются для получения результатов запросов, обновления, добавления и удаления данных. Если у приложения есть нужные полномочия, оно может запрашивать и модифицировать соответствующие данные, принадлежащие другому приложению, в том числе данные стандартных БД Android. В общем случае, контент-провайдеры следует создавать только тогда, когда требуется предоставить другим приложениям доступ к данным вашего приложения. В остальных случаях рекомендуется использовать СУБД (SQLite). Тем не менее, иногда контент-провайдеры используются внутри одного приложения для поиска и обработки специфических запросов к данным. Использование контент-провайдеров Для доступа к данным какого-либо контент-провайдера используется объект класса ContentResolver, который можно получить с помощью метода getContentResolver контекста приложения для связи с поставщиком в качестве клиента: ContentResolver cr = getApplicationContext().getContentResolver(); Объект ContentResolver взаимодействует с объектом контент-провайдера, отправляя ему запросы клиента. Контент-провайдер обрабатывает запросы и возвращает результаты обработки. Контент-провайдеры представляют свои данные потребителям в виде одной или нескольких таблиц подобно таблицам реляционных БД. Каждая строка при этом является отдельным «объектом» со свойствами, указанными в соответствующих именованных полях. Как правило, каждая строка имеет уникальный целочисленный индекс и именем «_id», который служит для однозначной идентификации требуемого объекта. Контент-провайдеры, обычно предоставляют минимум два URI для работы с данными: один для запросов, требующих все данные сразу, а другой – для обращения к конкретной «строке». В последнем случае в конце URI добавляется /<номер-строки> (который совпадает с индексом «_id»). Запросы на получение данных Запросы на получение данных похожи на запросы к БД, при этом используется метод query объекта ContentResolver. Ответ также приходит в виде курсора, «нацеленного» на результирующий набор данных (выбранные строки таблицы): ContentResolver cr = getContentResolver(); // получить данные всех контактов Cursor c = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); // получить все строки, где третье поле имеет конкретное // значение и отсортировать по пятому полю String where = KEY_COL3 + "=" + requiredValue; String order = KEY_COL5; Cursor someRows = cr .query(MyProvider.CONTENT_URI, null, where, null, order); Извлечение данных-результатов запроса с помощью курсора было рассмотрено ранее. Изменение данных Для изменения данных применяются методы insert, update и delete объекта ContentResolver. Для массовой вставки также существует метод bulkInsert. Пример добавления данных: ContentResolver cr = getContentResolver(); ContentValues newRow = new ContentValues(); // повторяем для каждого поля в строке: newRow.put(COLUMN_NAME, newValue); Uri myRowUri = cr.insert(SampleProvider.CONTENT_URI, newRow); // Массовая вставка: ContentValues[] valueArray = new ContentValues[5]; // здесь заполняем массив // делаем вставку int count = cr.bulkInsert(MyProvider.CONTENT_URI, valueArray); При вставке одного элемента метод insert возвращает URI вставленного элемента, а при массовой вставке возвращается количество вставленных элементов. Пример удаления: ContentResolver cr = getContentResolver(); // удаление конкретной строки cr.delete(myRowUri, null, null); // удаление нескольких строк String where = "_id < 5"; cr.delete(MyProvider.CONTENT_URI, where, null); Пример изменения: ContentValues newValues = new ContentValues(); newValues.put(COLUMN_NAME, newValue); String where = "_id < 5"; getContentResolver().update(MyProvider.CONTENT_URI, newValues, where, null); Лабораторная работа «получение списка контактов» Для чтения информации о контактах используется контент-провайдер ContactsContract, точнее, один из его подклассов. Для этой лабораторной работы воспользуемся провайдером ContactsContract.Contacts. Для чтения контактов приложению требуются полномочия READ_CONTACTS. Добавьте несколько контактов в эмуляторе (поскольку требуется только отображаемое имя контакта, остальные поля можно не заполнять :). Создайте новый проект ContactsSample. Выведите имена всех контактов (с помощью ListView), используя для получения информации URI ContactsContract.Contacts.CONTENT_URI. Необходимое имя поля для привязки адаптера найдите среди статических констант класса ContactsContract.Contacts. Создание контент-провайдеров Для создания собственного контент-провайдера требуется расширить класс ContentProvider и переопределить метод onCreate, чтобы проинициализировать источник данных, который требуется опубликовать. Остальные методы этого класса будут, по сути, обертками вокруг методов работы с исходным источником данных. Каркас для класса показан ниже: public class NewProvider extends ContentProvider { public final static Uri CONTENT_URI=Uri.parse("URI провайдера"); @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // Удаление данных return 0; } @Override public String getType(Uri uri) { // Возвращает тип MIME для указанных объектов(объекта) return null; } @Override public Uri insert(Uri uri, ContentValues values) { // Добавление данных return null; } @Override public boolean onCreate() { // Инициализация источника данных return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // Стандартный запрос return null; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // Обновление данных return 0; } } Как говорилось выше, URI обычно выглядят примерно так: content://<домен-разработчика-наоборот>.provider.<имя-приложения>/<путь-к-даным> Традиционно URI должны быть представлены двумя способами, одним – для доступа ко всем значениям определенного типа, другой – для указания на конкретный экземпляр данных. Например, URI content://com.android.provider.metropicker/stations мог бы использоваться для получения списка всех станций (метро), а content://com.android.provider.metropicker/stations/17 – для станции с индексом 17. При создании контент-провайдера обычно применяется статический объект класса UriMatcher, который служит для определения деталей запроса к контент-провайдеру. Использование UriMatcher позволяет «разгрузить» логику программы и избежать множественного сравнения строковых объектов за счет централизованного «отображения» URI разных видов на целочисленные константы. Особенно он полезен в случаях, когда создаваемый контент-провайдер обслуживает разные URI для доступа к одному и тому же источнику данных. Использовать UriMatcher очень просто: внутри класса контент- провайдера можно добавить такой код: // Константы для разных типов запросов private static final int ALL_STATIONS= 1; private static final int SINGLE_STATION= 2; private static final UriMatcher uriMatcher; // Заполнение UriMatcher'а // Если URI оканчивается на /stations - это запрос про все станции // Если на stations/[ID] - про конкретную станцию static { uriMatcher= new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("com.example.provider.metropicker", "stations", ALL_STATIONS); uriMatcher.addURI("com.example.provider.metropicker", "stations/#", SINGLE_STATION); } В дальнейшем полученный в запросе к контент-провайдеру URI проверяется в методах класса следующим образом: @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { switch (uriMatcher.match(uri)) { case ALL_STATIONS: // Вернуть курсор, указывающий на выборку со // всеми станциями case SINGLE_STATION: // Вытащить ID станции из URI: String _id = uri.getPathSegments().get(1); // Вернуть курсор, указывающий на выборку с одной // станцией. } return null; } При наполнении объекта UriMatcher шаблонами могут применять в «#» и «*» в качестве специальных символов: # в шаблоне совпадает с любым числом, а * - с любым текстом. Кроме уникальных URI, используемым создаваемым контент-провайдером, для определения клиентами типа возвращаемых по запросу данных используются уникальные типы MIME. Метод getType класса ContentProvider обычно возвращает один тип данных для массовой выборки, а другой – для одиночных записей. В нашем случае это могло бы выглядеть так: @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case ALL_STATIONS: return "vnd.com.example.cursor.dir/station"; case SINGLE_STATION: return "vnd.com.example.cursor.item/station"; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } Для того, что бы Android знал о существовании и мог использовать (через ContentResolver) ваш контент-провайдер, его нужно описать в Манифесте приложения. Минимальное описание выглядит так: android:name=".NewProvider" android:authorities="com.android.provider.metropicker"> В данном случае указаны только обязательные атрибуты элемента : имя класса контент-провайдера и его область ответственности. Более полную информацию о возможных атрибутах можно получить на сайте developer.android.com: http://developer.android.com/guide/topics/manifest/provider-element.html Лабораторная работа «создание контент-провайдера» Цель данной лабораторной работы – получить навыки создания собственных контент- провайдеров. В качестве основы возьмите упражнение «работа с SQLite с классом- адаптером» и замените прямое обращение к СУБД на взаимодействие с контент- провайдером, который будет инкапсулировать все взаимодействие с «настоящими» данными в отдельном классе. |