использование ContentProviderClient против ContentResolver для доступа к поставщику контента - PullRequest
61 голосов
/ 23 февраля 2011

Документация о поставщиках контента Android описывает использование ContentResolver, полученного из getContentResolver(), для доступа к контенту.

Однако есть также ContentProviderClient, который можно получить из getContentResolver().acquireContentProviderClient(authority). Кажется, он предоставляет более или менее те же методы, которые доступны в ContentResolver для доступа к контенту от провайдера.

Когда мне следует использовать ContentProviderClient вместо того, чтобы просто использовать ContentResolver напрямую? Каковы преимущества?

Ответы [ 5 ]

90 голосов
/ 08 марта 2011

Ваше устройство Android имеет много баз данных, каждая из которых идентифицируется уникальным Content Authority. Это эквивалентная часть «доменного имени» в содержимом: // uri - все до первой косой черты.

ContentResolver хранит данные с отображением от String contentAuthority до ContentProvider. Когда вы вызываете ContentResolver.query() или update() или что-то еще, URI разбирается на его компоненты, строка contentAuthority идентифицируется, и contentResolver должен найти на этой карте соответствующую строку и направить запрос нужному поставщику. , Этот дорогостоящий поиск происходит во время каждого отдельного вызова, потому что URI может отличаться от вызова к вызову, но также с другим contentAuthority. Кроме того, могут быть некоторые затраты, связанные с установлением и разрывом соединения с этим конкретным провайдером - его нельзя использовать повторно во всех вызовах. Я не уверен в накладных расходах, это довольно глубокий код уровня ОС.

В отличие от этого, когда вы звоните acquireContentProviderClient(authority), что "какой провайдер мне нужен?" поиск выполняется один раз, и вы получаете ContentProviderClient, который по сути является прямой ссылкой на ContentProvider. (Между вами и провайдером есть немного клея, который включает межпотоковое взаимодействие и параллелизм). Однако, когда вы используете ContentProviderClient, вы будете напрямую обращаться к поставщику за запрашиваемыми вами полномочиями. Это избавляет от необходимости постоянно пересматривать "какой провайдер мне нужен?"

ПРИМЕЧАНИЕ: За документация acquContentProviderClient () : если вы получаете ContentProviderClient, "Вызывающий должен указать, что он сделал с провайдером, вызвав ContentProviderClient .release () , который позволит системе освободить провайдера, если он определит, что нет других причин сохранять его активным. " Таким образом, если оставить устаревшего клиента открытым, то Провайдер будет продолжать работать как сервис в фоновом режиме. Итак, не забудьте убрать!

Резюме:

Множество звонков с различным контентом. Полномочия: Использование ContentResolver.

Повторные вызовы в один и тот же орган: Получить и использовать ContentProviderClient. Не забудьте отпустить (), когда закончите.

7 голосов
/ 29 октября 2012

Хорошо, но имейте в виду, что он работает только тогда, когда ContentProvider работает в том же процессе, что и Activity.

Примечание из документации по методу getLocalContentProvider():

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

4 голосов
/ 23 июля 2012

Я думаю, что еще одно отличие импорта заключается в том, что ContentProviderClient может быть преобразован в объект пользовательского провайдера и иметь доступ к другому методу, кроме CRUD.

ContentProvider cp = getContentResolver().acquireContentProviderClient(mCurUri).getLocalContentProvider();
yourProvider fld = (yourProvider)cp;
fld.query(...);           // you can query as ContentResolver
fld.addFolder(newFolder); // also can invoke the extend method of your custom ContentProvider
2 голосов
/ 10 марта 2012

Я обнаружил следующую разницу: Я написал свой собственный контент-провайдер в приложении А. Я написал виджет рабочего стола в приложении Б. Когда я попытался получить доступ к ContentProvider приложения A через ContentResolver из моего виджета, я получил ошибку «не удалось найти информацию о поставщике». Когда я вместо этого получал бы ContentProviderClient через ContentResolver и запрашивал через ContentProviderClient, это работало бы. Мне пришлось ничего не менять, только использовать ContentProviderClient вместо ContentResolver. У меня нет реального объяснения этому поведению, и я не нашел никакой информации в Интернете, почему это так. Я не знаю, является ли это особой причудой виджетов, потому что я не пробовал ее из действия в приложении B (приложение B - простой виджет, без активности).

0 голосов
/ 08 апреля 2016

Одно из применений ContentProviderClient полезно для доступа к некоторым методам ContentProvider при тестировании. Например, я использую метод shutdown () в модульных тестах, чтобы избежать нескольких тестов, создающих несколько поставщиков контента.

Реализация ContentProvider#shutdown() как это:

@Override
public void shutdown() {
    openHelper.close();
    super.shutdown();
}

И в конце метода теста вызовите shutdown(), используя ContentProviderClient, чтобы очистить тест, чтобы другие тесты могли использовать провайдер контента:

getContext()
       .getContentResolver()
       .acquireContentProviderClient(URI)
       .getLocalContentProvider()
       .shutdown();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...