Перейти к содержимому

Content provider android что это

  • автор:

Принципы работы поставщиков содержимого

Существует два класса, участвующих во взаимодействии ContentProvider :

  • ContentProvider — реализует API, который предоставляет набор данных стандартным способом. Основные методы — это Query (запрос), Insert (вставка), Update (обновление) and Delete (удаление).
  • ContentResolver — статический прокси-сервер, который обменивается данными с ContentProvider для доступа к данным из того же приложения или из другого приложения.

Поставщик содержимого обычно использует базу данных SQLite, но API означает, что для использования кода потребителя не нужно ничего знать о базовом SQL. Запросы выполняются через универсальный код ресурса (URI), в котором для имен столбцов используются константы (чтобы уменьшить зависимости от базовой структуры данных), и для кода потребителя, по которому выполняется итерация, возвращается ICursor .

Использование ContentProvider

ContentProviders предоставляет свои функциональные возможности через URI, зарегистрированный в AndroidManifest.xml приложения, которые публикуют данные. Существует соглашение о том, что предоставляемые URI и столбцы данных, должны быть доступны в виде констант, чтобы упростить привязку к данным. Встроенные ContentProviders в Android предоставляют удобные классы с константами, которые ссылаются на структуру данных в пространстве имен Android.Providers .

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

Android предоставляет доступ к широкому спектру системных и пользовательских данных с помощью ContentProviders :

  • Браузер — закладки и журнал браузера (требуется разрешение READ_HISTORY_BOOKMARKS и (или WRITE_HISTORY_BOOKMARKS ) ).
  • CallLog — недавние вызовы, выполненные или полученные с устройства.
  • Контакты — подробная информация из списка контактов пользователя, включая людей, телефоны, группы фотографий & .
  • MediaStore — содержимое устройства пользователя: аудио (альбомы, художники, жанры, списки воспроизведения), изображения (включая эскизы) & видео.
  • Параметры — параметры и настройки устройства для всей системы.
  • UserDictionary — содержимое определяемого пользователем словаря, используемого для прогнозного текстового ввода.
  • Голосовая почта — журнал сообщений голосовой почты.

Общие сведения о классах

Ниже показаны основные классы, используемые при работе с ContentProvider .

Схема классов с приложением поставщика содержимого и взаимодействием с приложением

На этой схеме ContentProvider реализует запросы и регистрирует URI, которые используются другими приложениями для нахождения данных. ContentResolver выступает в качестве посредника для ContentProvider (методы Query, Insert, Update и Delete). SQLiteOpenHelper содержит данные, используемые ContentProvider , но он не предоставляется напрямую приложениям-потребителям. CursorAdapter передает курсор, возвращаемый ContentResolver , для вывода в ListView . UriMatcher — это вспомогательный класс, который анализирует коды URI при обработке запросов.

Назначение каждого класса дано ниже.

  • ContentProvider — реализует методы этого абстрактного класса для предоставления данных. API доступен для других классов и приложений через атрибут URI, который добавляется в определение класса.
  • SQLiteOpenHelper — помогает реализовать хранилище данных SQLite, предоставляемое ContentProvider .
  • UriMatcher — используйте UriMatcher в реализации ContentProvider для управления URI, которые используются для запроса содержимого.
  • ContentResolver — при использовании кода для доступа к экземпляру ContentProvider используется ContentResolver . Эти два класса совместно устраняют проблемы межпроцессного взаимодействия, позволяя легко обмениваться данными между приложениями. Код потребителя никогда не создает класс ContentProvider явным образом. Вместо этого доступ к данным осуществляется путем создания курсора на основе URI, предоставляемого приложением ContentProvider .
  • CursorAdapter — используйте CursorAdapter или SimpleCursorAdapter для отображения данных, доступных через ContentProvider .

API ContentProvider позволяет приложениям-потребителям выполнять различные операции с данными, например:

  • запрашивать данные для возврата списков или отдельных записей;
  • изменять отдельные записи;
  • добавлять новые записи;
  • удалять записи.

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

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

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

Метод 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.

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

Препарирование ContentProvider

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

  • https://www.youtube.com/watch?v=3HhBKfjuvf4 — ContentProvider & Loader (обзор)
  • https://www.youtube.com/watch?v=QEqGgmMkRDk — ContentProvider & SQLite (опыт использования)
  • https://www.youtube.com/watch?v=zeDzbzLmpLs — ContentProvider (опыт использования)
  • http://www.nerdgrl.org/ru/programming/sqlite-contentprovider-1/ — цикл статей ContentProvider & SQLite
  • https://ru.stackoverflow.com/questions/653346/%D0%A7%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-contentprovider — Ответ на русском StackOverflow “Что такое ContentProvider?”
  • https://www.tutorialspoint.com/android/android_content_providers.htm — Tutorial ContentProvider
  • https://www.youtube.com/watch?v=xHXn3Kg2IQE — классика (паттерны A/B/C)
  • https://stackoverflow.com/questions/39825125/android-recyclerview-cursorloader-contentprovider-load-more — Tutorial ContentProvider & SQLite

Задуман, как способ предоставлять данные вашего приложения для сторонних приложений, + для реализации поиска среди данных вашего приложения с использованием 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 говорит следующее:

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

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

  • Для каждой сущности ContentProvider’a есть свой URI.
  • Регистрация в манифесте ContentProvider’a выглядит следующим образом (пока без пояснения и др. возможных атрибутов):
 android:name=".peopleprovider" android:authorities="io.github.ziginsider.peopleprovider" android:exported="false"/>
  • рекомендуется использовать в качестве 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 – это номер добавленного экземпляра.

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

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

public boolean onCreate()
  • инициализирует ContentProvider. Провайдер будет создан как только вы обратитесь к нему с помощью ContentResolver’a. Возвращает true, если ContentProvider создан успешно. В общем случае, не рекомендуется делать в onCreate() ContentProvider’a длительных операций т.к. это может повесить onCreate() Application (??)
public Cursor query(@NonNull Uri uri, // The content URI of the words table (FROM table_name) String[] projection, // The columns to return for each row (col, col, col, . ) String selection, // Selection criteria (WHERE col = value) String[] selectionArgs, // Selection criteria args (instead '?') String sortOrder) // The sort order for the returned rows (ORDER BY col, col, . )
  • Возвращает объект Cursor по полученному URI. URI парсится, согласно заданным нами правилам. В случае использования в качестве источника данных БД SQLite извлекает данные из БД, и возвращает их в виде Cursor. (соответствует HTTP методу GET).
public Uri insert(@NonNull Uri uri, ContentValues values)
  • добавляет новые данные, возвращает URI новой записи. (соответствует HTTP методу POST)
public final int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values)
  • добавляет массив элементов (не является обязательным для реализации в отличии от всех остальных методов)
public final int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs)
  • обновляет строки в хранилище данных согласно заданным условиям. (в терминологии HTTP методов – PUT или PATCH)
public final int delete(@NonNull Uri uri, String selection, String[] selectionArgs)
  • удаляет данные. ( единственный метод ContentProvider, HTTP аналог которого имеет такое же название)
public final String getType(@NonNull Uri uri)
  • возвращает MIME-тип для заданной content URI. Обычно этот метод используют для сопоставления имени таблицы и URI, чтобы потом выполнить запрос к базе данных.

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

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

Cursor cursor = mContext.getContentResolver().query(table.getUri(), null, where.where(), where.whereArgs(), where.limit());

Манифест

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

provider android:authorities="list" android:directBootAware=["true" | "false"] android:enabled=["true" | "false"] android:exported=["true" | "false"] android:grantUriPermissions=["true" | "false"] android:icon="drawable resource" android:initOrder="integer" android:label="string resource" android:multiprocess=["true" | "false"] android:name="string" android:permission="string" android:process="string" android:readPermission="string" android:syncable=["true" | "false"] android:writePermission="string" > . . . provider>

Атрибут 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 для стороннего приложения.

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

 android:name="bbct.android.common.BaseballCardProvider" android:label="@string/provider_name" android:authorities="bbct.android.baseballcard" android:readPermission="bbct.android.lite.permission.READ" />

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

 android:name="bbct.android.lite.permission.READ" />

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

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

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

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

  • :// — “content://”
  • — уникальный идентификатор нашего ContentProvider’a. Вместе с составляет базовый URI — часть которая будет присутствовать во всех запросах к нашему ContentProvider’у. Еще раз скажем, что его нужно делать уникальным. Обычно составляется по приципу “имя_пакета + имя_приложения + имя_провайдера”.

UriMatcher

UriMatcher — класс Android SDK, который хранит соответствие между URI и неким заданным значением integer. Это значение можно использовать в операторе switch, чтобы описать поведение для каждого Content URI. Весьма нужная штука для работы c ContentProvider’ом.

Два метода, которые необходимо знать void AddUri(String authority, String path, int code) и int match(Uri uri). Первый ставит в соответствие path (т.е., по-сути, Uri) и code (надеюсь, что такое authority объяснять не надо), второй по uri возвращает code. Данный класс используется для разбора Uri в REST-методах ContentProvider’a (getType(), query(), etc.) для идентификации действия по URI-запросу. Ниже мы полностью рассмотрим его применение на своем месте, пока — основновные моменты использования:

private static final UriMatcher sUriMatcher;
sURIMatcher.addURI("contacts", "people", PEOPLE); // PEOPLE = unique integer constant

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

public String getType(Uri url)  int match = sURIMatcher.match(url); switch (match)  case PEOPLE: return "vnd.android.cursor.dir/person"; . . .

Практика использования Content Provider’a

18 08 2017

  • Java
    • Android Quizzes 2021
    • Реактивное программирование с применением RxJava
    • Android изнутри. Часть I
    • Большие запросы к базе данных на Android
    • ProgressDialog умер, да здравствует ProgressBar!
    • Введение в Android Architecture Components
    • Firebase Tutorial. Part II. — Как автоматически развернуть сайт на хостинге Firebase из GitHub-репозитория?
    • Firebase Tutorial — Firebase database. Part I.
    • У меня было 10 Android собеседований за последние два года. (перевод)
    • Android Tutorial — Facebook SDK Login. Part III. Get Posts.
    • Android Tutorial — Facebook SDK Login. Part II. Share content.
    • Android Tutorial — Facebook SDK Login. Part I.
    • Оптимизация прокрутки вложенных в друг друга RecyclerView
    • RecyclerView и ListView. В чем разница?
    • Различные типы Item View в RecyclerView
    • Тесты сделают вас счастливее (перевод).
    • Пример анимации в Android с использованием TimeAnimator.
    • Android. Два способа записать результат Timer в пользовательский поток (UI Thread).
    • Видео. Architecture Components. Solving the Lifecycle Problem. Перевод субтитров.
    • Зачем нужны интерфейсы в ООП?
    • Видео. Architecture Components. Improve Your App’s Design. Перевод субтитров.
    • Видео. Google I/O ’17 Architecture Components — Introduction. Перевод субтитров.
    • Препарирование ContentProvider
    • REST. Описание концепции. Особенности реализации API. Максимально кратко.
    • Лоадеры (loaders) в Android. Для чего нужны. Конспект.
    • Volley vs Retrofit. Описание библиотек REST API.
    • Краткий конспект реализации Garbage Collector в Java
    • Препарирование RecyclerView
    • Лексикон прописных истин Android
    • Android Quizzes 2021
    • Review Currency App task.
    • Foreground Service Android demo App — stopwatch
    • Simple Custom View demo App — circular progress bar
    • Simple RecyclerView demo App — Stopwatch
    • RS School Android 2021
    • Реактивное программирование с применением RxJava
    • Android изнутри. Часть I
    • Большие запросы к базе данных на Android
    • ProgressDialog умер, да здравствует ProgressBar!
    • Введение в Android Architecture Components
    • Firebase Tutorial. Part II. — Как автоматически развернуть сайт на хостинге Firebase из GitHub-репозитория?
    • Firebase Tutorial — Firebase database. Part I.
    • У меня было 10 Android собеседований за последние два года. (перевод)
    • Android Tutorial — Facebook SDK Login. Part III. Get Posts.
    • Android Tutorial — Facebook SDK Login. Part II. Share content.
    • Android Tutorial — Facebook SDK Login. Part I.
    • Оптимизация прокрутки вложенных в друг друга RecyclerView
    • RecyclerView и ListView. В чем разница?
    • Различные типы Item View в RecyclerView
    • Тесты сделают вас счастливее (перевод).
    • Пример анимации в Android с использованием TimeAnimator.
    • Android. Два способа записать результат Timer в пользовательский поток (UI Thread).
    • Видео. Architecture Components. Solving the Lifecycle Problem. Перевод субтитров.
    • Зачем нужны интерфейсы в ООП?
    • Видео. Architecture Components. Improve Your App’s Design. Перевод субтитров.
    • Видео. Google I/O ’17 Architecture Components — Introduction. Перевод субтитров.
    • Препарирование ContentProvider
    • REST. Описание концепции. Особенности реализации API. Максимально кратко.
    • Лоадеры (loaders) в Android. Для чего нужны. Конспект.
    • Volley vs Retrofit. Описание библиотек REST API.
    • Несколько примеров на Kotlin
    • Препарирование RecyclerView
    • Лексикон прописных истин Android
    • Xamarin.Forms. Layouts — виды
    • Xamarin.Forms. Оптимизация ListView.
    • Xamarin.Forms. Ускорение отображения окна (Activity)
    • Платформозависимость на Xamarin
    • Препарирование ContentProvider

    Что такое Content Provider?

    В недавней статье описывается архитектура приложения, в котором присутсвует определние Content Provider’a:

    Контент провайдер очень мощная штука с уведомлениями об изменениях данных и это все из коробки. Юзаем в основном как обвертку над базой. Способа как туда правильно впихнуть загрузку данных из инета не нашел.

    В документации абсолютно другое:

    Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications.

    Т.е. по видимому автор статьи имел ввиду другой Контент провайдер, или нет?

    • Вопрос задан более трёх лет назад
    • 6294 просмотра

    Комментировать
    Решения вопроса 0
    Ответы на вопрос 3

    Правильно в документации: компонент, раздающий данные для нескольких приложений (хотя может и только одному, но сама идея компонента в предоставлении доступа к данным для нескольких приложений). Речь об одном и том же. В Android есть только один Content Provider.

    Ответ написан более трёх лет назад
    Комментировать
    Нравится Комментировать
    nonrblGyN4ik @nonrblGyN4ik
    Нет, просто автор статьи не обладает даром понятного объяснения:)
    Ответ написан более трёх лет назад
    Комментировать
    Нравится Комментировать

    atetc

    Админ Android dev-s чата: https://goo.gl/8JKF1f

    Content Provider — сущность, являющаяся независимой оберткой над источниками данных (бизнес-логика приложения может даже не знать как именно она устроена: БД, файлы, сервер или еще что-то), которая также следует REST-подобной архитектуре и стремится привести данные в обобщенный тип.

    Кратко можно тут ознакомиться habrahabr.ru/post/132720

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *