Подтвердить что ты не робот

Использование ContentProviderClient vs ContentResolver для доступа к поставщику контента

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

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

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

4b9b3361

Ответ 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();