Использование ContentProviderClient vs ContentResolver для доступа к поставщику контента
Документация для поставщиков контента Android описывает использование ContentResolver
, полученного из getContentResolver()
, для доступа к контенту.
Однако существует также a ContentProviderClient
, которое можно получить из getContentResolver().acquireContentProviderClient(authority)
. Кажется, он предоставляет более или менее те же методы, доступные в ContentResolver
для доступа к контенту от поставщика.
Когда следует использовать ContentProviderClient
вместо прямого использования ContentResolver
? Каковы преимущества?
Ответы
Ответ 1
В вашем устройстве Android есть много баз данных, каждый из которых идентифицируется уникальным авторитетом контента. Это эквивалентная часть "доменного имени" в содержимом://uri - все до первой косой черты.
ContentResolver
хранит данные, обеспечивающие отображение от String contentAuthority
до ContentProvider
. Когда вы вызываете ContentResolver.query()
или update()
или что у вас есть, URI анализируется отдельно на его компоненты, строка contentAuthority идентифицируется, а contentResolver должен искать эту карту для соответствующей строки и направлять запрос правильному провайдеру, Этот дорогостоящий поиск происходит во время каждого отдельного вызова, потому что URI может отличаться от вызова к вызову, с другим свойством contentAuthority. Кроме того, могут возникнуть некоторые издержки, связанные с настройкой и разрывом соединения с этим конкретным провайдером - он не может использоваться повторно между вызовами. Я не уверен в том, что накладные расходы там связаны, что довольно глубокий код уровня ОС.
В отличие от этого, когда вы вызываете acquireContentProviderClient(authority)
, что "какой-то провайдер мне нужен?" поиск выполняется один раз, и вам предоставляется ContentProviderClient
, который по существу является прямой ссылкой на ContentProvider
. (Там есть немного клея между вами и провайдером, который использует межпоточную связь и блокировку concurrency). Однако, когда вы используете ContentProviderClient
, вы будете напрямую обращаться к Поставщику за запрошенным вами органом. Это избавляет от ненужного перераспределения "какого провайдера я хочу?"
ПРИМЕЧАНИЕ. В документации приобретатьContentProviderClient(): Если вы получаете ContentProviderClient, "вызывающий должен указать, что они выполняются с провайдером вызвав ContentProviderClient.release(), который позволит системе освободить поставщика, и он определяет, что нет никакой другой причины для поддержания его активности". Поэтому, по существу, оставляя устаревшего клиента открытым, заставит Провайдер продолжать работать как услуга в фоновом режиме. Итак, не забудьте очистить!
Резюме:
Многие вызовы различного контента. Авторизация: Используйте ContentResolver
.
Повторные вызовы для того же органа: Получить и использовать ContentProviderClient
. Не забудьте освободить(), когда вы закончите.
Ответ 2
Хорошо, но имейте в виду, что он работает только тогда, когда ContentProvider работает в том же процессе, что и Activity.
Примечание к документации для метода getLocalContentProvider()
:
Если ContentProvider работает в другом процессе, то null будут возвращены. Это можно использовать, если вы знаете, что работаете в тот же процесс, что и поставщик, и хотите получить прямой доступ к его подробности реализации.
Ответ 3
Я думаю, что другая разница в различиях заключается в том, что 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
Ответ 4
Я нашел следующее различие:
Я написал свой собственный contentprovider в приложении A.
Я написал виджет домашнего экрана в приложении Б.
Когда я попытался получить доступ к ContentProvider приложения A через ContentResolver из моего виджета, я получил сообщение "не удалось найти информацию о провайдере".
Когда я вместо этого получаю ContentProviderClient через ContentResolver и запрашиваю через ContentProviderClient, он будет работать.
Мне больше ничего не нужно было менять, используйте ContentProviderClient вместо ContentResolver.
У меня нет реального объяснения этого поведения и не было обнаружено никакой информации в Интернете, почему это так.
Я не знаю, если это особый причуд виджетов, потому что я не пробовал его из активности в приложении B (приложение B - простой виджет, без активности).
Ответ 5
Одно из применений ContentProviderClient полезно для доступа к некоторым из методов ContentProvider при тестировании. Например, я использую метод shutdown() в модульных тестах, чтобы избежать нескольких тестов, создающих несколько поставщиков контента.
Внесите ContentProvider#shutdown()
следующим образом:
@Override
public void shutdown() {
openHelper.close();
super.shutdown();
}
И в конце метода тестирования вызовите shutdown()
с помощью ContentProviderClient
, чтобы очистить тест, чтобы другие тесты могли использовать поставщика контента:
getContext()
.getContentResolver()
.acquireContentProviderClient(URI)
.getLocalContentProvider()
.shutdown();