1

複数のクライアント アプリに REST ベースの検索結果を提供する apk にコンテンツ プロバイダーがあります。

基本的に、クライアントはコンテンツ リゾルバを介してカーソルをリクエストし、インテント サービス リクエストを起動して検索をトリガーします。

プロバイダーでは、カーソルがテーブルに返され、各インテント サービス リクエストが対応するテーブルに入力され、NotifyDataSetChanged がトリガーされます。

私が抱えている唯一の問題は、プロバイダーが何らかの理由で強制終了された場合 (pkill -9 com.myprovider.name を実行してテスト)、クライアント apk のカーソルは変更されませんが、アプリには通知されないことです。プロバイダーがなくなり、データベースに再接続する必要がある..したがって、サービスインテントを起動し続け、カーソルは更新されません.

コードを調べて、根本的な問題を隠している可能性のあるいくつかの例外をキャッチしているかどうかを確認しましたが、表示されていません..

finalize / onLowMemory / shutdown() のプロバイダーで明示的にcursor.close()を実行しようとしました。トリガーされたようには見えません。

これはlogcatで発生することに気付きました

09-10 13:58:03.015: I/ActivityThread(4268): Removing dead content provider: com.myprovider.name (called from the calling app)

呼び出し元のアプリからこの通知を取得する方法はありますか?

4

1 に答える 1

0

したがって、いくつかの調査の後、実行可能な解決策がありますが、他の提案があれば、いただければ幸いです。

contentProvider を使用してカーソルを取得しているため、IntentService を介してバックエンド データを更新するだけです。ユーザーが検索の最初の文字を入力したときにカーソルを取得し、カーソル数 = 0 の場合は空のリスト メッセージを表示し、それ以外の場合はそのカーソル内のアイテムのリストを表示します。

** 注: カーソル処理の一部を少し調整する必要がある場合があります。アダプタでカーソルが切り取られて null になることによるクラッシュは見られませんでしたが、マイレージは異なる場合があります.. (これは、 contentProviderClient() )

** 注意: ドキュメントによると、 contentProviderClient() を使用しない場合は解放する必要があります。

コンテンツ プロバイダーは型を返す必要があるため、次のことができます。

そこで、メンバー変数を定義します

private ContentProviderClient contentProviderClient = null;

次に、ユーザーが検索文字列を変更すると、最終的に呼び出します

public void setFilter( String searchFilter ) {
   searchedString = !TextUtils.isEmpty(filter) ? filter : "";

   boolean reload = false;               // Reloads content provider

   // contentProvider is null on first connection, assumed to be up on 
   // subsequent connections as we only close the cursor and 
   // contentProviderClient when we exit

   if (contentProviderClient != null) {
      try {
      // getType will throw an exception if the instance of the 
      // contentProvider went away (killed by user/memory collection etc)

         contentProviderClient.getType(searchFactoryUri);
      } catch (RemoteException e) {
         if( searchAdapter != null ) {
            Cursor cursor = searchAdapter.getCursor();
            cursor = null; 
            reload = true;
            contentProviderClient.release();
         }
      }
   }

   // This is for first search initialization or reloading cursor 
   // if the content provider went away for some unknown reason.

   if( this.searchAdapter == null || reload ){
      Cursor cursor = getActivity().getContentResolver().query(
            MY_URI,
            null,
            null,
            null,
            null);

   contentProviderClient = getActivity()
             .getContentResolver()
             .acquireContentProviderClient(MY_URI);

   cursor.setNotificationUri(getActivity.getContentResolver(), MY_URI);

   // DO what ever you need to after getting cursor, a cursor loader
   // would be a better implementation here, but simplifying it as 
   // I don't want to over-complicate the example.

   myList.setAdapter(searchAdapter);

   }
   getActivity().startService(MyUtil.getSearchIntent( MY_URI, searchedString );
}

@Override
public void onDestroy() {
   super.onDestroy();
   // Cleanup adapter, cursor, provider client
   if (searchAdapter != null) {
      searchAdapter.changeCursor(null); // Closes existing cursor 
   }
   if (contentProviderClient != null) {
     contentProviderClient.release();  // Release client
   }
}
于 2012-09-12T13:05:34.190 に答える