在内容提供商中调用API以进行全局搜索

时间:2014-10-01 02:55:33

标签: android android-tv

我们正试图连接我们的AndroidTV应用,将结果附加到全球搜索中。我遇到了一个问题,我无法通过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调用,我会得到一个networkonmainthreadexception。

我试图通知光标数据已经改变,但也没有成功。

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

无论如何我可以强制O.S在一个单独的线程上调用内容提供者,或者至少通知搜索光标有新的内容吗?

谢谢

4 个答案:

答案 0 :(得分:6)

其中一个解决方案是设置内容提供商流程

android:process:":androidtv"

并在进行网络呼叫之前将ThreadPolicy设置为LAX

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

通过在不同的进程中运行contentprovider,即使查询在主线程上运行,也不会影响您的UI操作

答案 1 :(得分:1)

我也一直在努力解决这个问题,因为我没有找到阻止用户界面接受的当前接受的答案。

然而,谷歌电视团队的MarcBächinger表示,这只是模拟器的一个问题。在更新的版本(例如当前可用硬件中的版本)中,搜索提供程序在后台线程中调用,这完全避免了这个问题。

我已经能够在Nexus播放器上测试它,并确认它能正常工作。

来源:https://plus.google.com/+DanielCachapa/posts/dbNMoyoRGEi

答案 2 :(得分:0)

编辑回答

我自己也经历过这个问题,我不得不依赖于已接受答案的解决方案。但是,我注意到在“全局搜索”中键入明显滞后。框。这种滞后是:

  1. 由应用程序引起,因为它的删除使得滞后消失
  2. 最有可能是由于查询应用程序的同步等待 - 由于我们的应用程序执行了两次网络请求,query()方法需要一段时间才能完成,从而导致此延迟
  3. 我发现不需要单独的流程(: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));
    }
    

答案 3 :(得分:0)

为了解决在查询方法中使用API​​在全局搜索中显示结果的问题,我所做的基本上是在api结果的获取与查询db的结果以返回游标之间引入延迟。

您可以通过

private Cursor getSuggestions(final String query) {
    Cursor cursor;
    cursor = getCursor(query);
    if (cursor==null || cursor.getCount() == 0) {
    //apiCall
      try {
        Thread.sleep(X millis);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      cursor = getCursor(query);
    }
    return cursor;
  }

我们将继续寻找是否可以在没有延迟的情况下重新挂钩。