2014-10-01 2 views
6

Мы пытаемся подключить наше приложение AndroidTV, чтобы добавить результаты в глобальный поиск. Я столкнулся с проблемой, когда я не могу сделать api-вызов для получения результатов, потому что система вызывает мой контент-провайдер в основном потоке.Call API в поставщике контента для глобального поиска

@Override 
public Cursor query(Uri uri, String[] projection, String search, String[] selectionArgs, String searchOrder) { 

    ... Logic here that calls the API using RxJava/Retrofit 

    return cursor; 
} 


<searchable xmlns:android="http://schemas.android.com/apk/res/android" 
android:label="@string/foo" 
android:searchSettingsDescription="@string/foo_results" 
android:includeInGlobalSearch="true" 
android:searchSuggestAuthority="com.foo.search.provider" 
android:searchSuggestIntentAction="android.intent.action.VIEW" /> 

<provider 
    android:authorities="com.foo.search.provider" 
    android:name=".search.GlobalSearchProvider" 
    android:exported="true"/> 

Когда я выполняю глобальный поиск, я вижу, что вызывается запрос ContentProvider #. Если я пытаюсь выполнить вызов api в текущем потоке, я получаю сетевое имя.

Я попытался изменить курсор, который изменил данные, но также не имел успеха.

getContext().getContentResolver().notifyChange(Uri.parse("content://com.foo.test"), null); 
... 
cursor.setNotificationUri(getContext().getContentResolver(), Uri.parse("content://com.foo.test")); 

Есть в любом случае я могу заставить O.S назвать контент-провайдера на отдельном потоке или, по крайней мере, уведомить поиска, что курсор имеет новое содержание?

Спасибо

ответ

6

Одним из решений может быть установка процессной содержание

android:process:":androidtv" 

и установите ThreadPolicy в LAX только перед принятием вызовов сети

ThreadPolicy tp = ThreadPolicy.LAX; 
StrictMode.setThreadPolicy(tp); 

Выполнив ContentProvider в другом процессе, даже если запрос выполняется в основном потоке, это не повлияет на работу вашего пользовательского интерфейса.

+0

Не могли бы вы, пожалуйста, посмотрите на мой ответ ниже? – Sebastiano

+0

@dextor Я думаю, вы можете попытаться изменить порядок, в котором ваш searchableinfo появляется в списке SearchManager.getSearchablesInGlobalSearch(). Я думаю, вы можете сделать это, изменив имя операции поиска. Так что ваш поиск приложения будет выполнен последним приложением для поиска, но я не уверен, что он сработает. Кроме того, точка создания отдельного процесса заключается в том, что запрос не запускается в основном потоке, если вы просто установите политику lax, запрос будет выполняться в основном потоке, а операции пользовательского интерфейса могут быть отложены или вы можете получить ANR – nandeesh

+0

Мои результаты поиска уже отображаются в качестве последнего результата, так что это не выход. Я знаю, что работа над отдельным процессом «решает» проблему, но я заметил, что возникающее отставание намного выше, чем при одном и том же процессе. И я не могу понять, почему. – Sebastiano

0

EDITED ОТВЕТ

Я испытал этот вопрос сам, и я должен был полагаться на предлагаемом решении принято отвечать в. Тем не менее, я заметил, что при вводе в поле «Глобальный поиск» есть заметное отставание. Это отставание:

  1. Вызванное применением, поскольку его удаление делает лаг исчезнет
  2. Скорее всего из-за синхронное ожидание на запрашиваемых приложениях - так как наше приложение делает два сетевых запросов, метод query() занимает много времени для завершения, в результате чего это отставание

Я выяснил, что отдельный процесс (:androidtv) не требуется. Установив конфигурацию ThreadPolicy.LAX, сетевой запрос будет выполняться без выброса NetworkOnMainThreadException.

Я до сих пор не понимаю, почему существует отставание.


ОРИГИНАЛЬНЫЙ ОТВЕТ

Я не верю, что принятый ответ, в то время как это, конечно, работает, это правильный путь сделать это.

После вызова метода query() вы должны создать новый поток/задачу/задание для выполнения сетевого вызова (поэтому, избегая NetworkOnMainThreadException), который обновит адаптер после получения желаемых данных.

Есть разные способы сделать это.Вы можете использовать обратный вызов или шину события (например, Otto). Это метод, который я называю, чтобы обновить адаптер:

public void updateSearchResult(ArrayList<Data> result) { 
    mListRowAdapter.clear(); 
    mListRowAdapter.addAll(0, result); 
    HeaderItem header = new HeaderItem(0, "Search results", null); 
    mRowsAdapter.add(new ListRow(header, mListRowAdapter)); 
} 
+0

Я не могу начать отдельный поток, потому что нет возможности, чтобы я мог вернуться к платформе AndroidTV, что данные в курсоре были обновлены. – Darussian

+0

Почему бы и нет? (возможно, я что-то пропустил) – Sebastiano

+0

Я не контролирую, что делает фреймворк, и у них нет никакой логики для меня, чтобы общаться с ней. – Darussian

0

Я также боролся с этим, как я не нашел принятый в настоящее время ответа блокирует UI приемлемым.

Однако, по словам Марка Бачингера из команды Google TV, это проблема только с эмулятором. В более поздних сборках (например, в доступном в настоящее время аппаратном обеспечении) поставщики поиска вызываются в фоновом потоке, что полностью исключает проблему.

Я смог протестировать его на Nexus Player и подтвердить, что он работает правильно.

Источник: https://plus.google.com/+DanielCachapa/posts/dbNMoyoRGEi

Смежные вопросы