7

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#query が呼び出されていることがわかります。現在のスレッドで API 呼び出しを実行しようとすると、networkonmainthreadException が発生します。

データが変更されたことをカーソルに通知しようとしましたが、成功しませんでした。

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

OSに別のスレッドでコンテンツプロバイダーを強制的に呼び出すか、少なくともカーソルに新しいコンテンツがあることを検索に通知させることができますか?

ありがとうございました

4

4 に答える 4

6

解決策の 1 つは、コンテンツ プロバイダー プロセスを設定することです。

android:process:":androidtv"

ネットワーク呼び出しを行う直前に ThreadPolicy を LAX に設定します

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

別のプロセスで contentprovider を実行することで、クエリがメイン スレッドで実行されても、UI 操作には影響しません。

于 2014-10-01T03:52:15.383 に答える
0

編集された回答

私はこの問題を自分で経験しており、受け入れられた回答の提案された解決策に頼らなければなりませんでした。ただし、 「グローバル検索」ボックスに入力するときに顕著な遅延があることに気付きました。このラグは次のとおりです。

  1. アプリケーションが原因で、削除するとラグがなくなるため
  2. ほとんどの場合、クエリされたアプリケーションでの同期待機が原因です。このアプリは 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));
}
于 2014-10-04T07:46:05.480 に答える
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;
  }

遅延を使用せずに何らかのフックを再接続できるかどうかを引き続き確認します。

于 2018-10-17T06:28:23.120 に答える