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


The документация на Android контент-провайдеров описывает с помощью ContentResolver, полученных от getContentResolver(), чтобы получить доступ к содержимому.

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

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

5 61

5 ответов:

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

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

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

Примечание: Per acquireContentProviderClient() документация: если вы получаете ContentProviderClient,"вызывающий абонент должен указать, что они закончили с провайдером, позвонив ContentProviderClient.release () что позволит системе освободить провайдера он определяет, что нет никакой другой причины для поддержания его активным." таким образом, по существу, оставляя устаревший клиент открытым, поставщик будет продолжать работать как Служба в фоновом режиме. Так, не забудьте очистить!

резюме:

многие звонки на различные contentAuthorities: использовать ContentResolver.

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

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

Примечание в документации для метода getLocalContentProvider():

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

Я думаю, что еще одно различие импорта-это 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

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

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

реализовать ContentProvider#shutdown() такой:

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

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

getContext()
       .getContentResolver()
       .acquireContentProviderClient(URI)
       .getLocalContentProvider()
       .shutdown();