内容提供程序w / Cursor - 获取Killed(如何通知客户端)

时间:2012-09-10 14:02:02

标签: android cursor android-contentprovider

我在apk上有一个内容提供商,它为多个客户端应用提供基于Rest的搜索结果。

基本上,客户端通过内容解析器请求游标,然后触发意图服务请求以触发搜索..

在提供程序中,游标返回到表,每个意图服务请求填充相应的表,并触发NotifyDataSetChanged。

工作得很好..我遇到的唯一问题是,如果提供商因某种原因被杀死(通过执行pkill -9 com.myprovider.name测试),客户端apk上的光标不会改变,但应用程序没有通知提供者离开,并且需要重新连接到数据库..所以它将继续启动服务意图,并且游标永远不会更新b / c它不再绑定到底层数据库。

我查看了我们的代码,试着看看我们是否捕获了一些异常,这可能隐藏了潜在的问题,但我没有看到它......

我尝试在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)

从调用应用程序获取此通知的任何方式?

1 个答案:

答案 0 :(得分:0)

经过一些研究,我有一个可行的解决方案,但如果有人有任何其他建议,他们将不胜感激。

由于我们使用contentProvider获取游标,因此只需通过IntentService更新后端数据。当我们的用户键入搜索的第一个字符时,我们抓取光标,如果光标数= 0,那么我们显示一个空的列表消息,否则我们显示该光标中的项目列表..

**注意:某些游标处理可能需要稍微调整,我没有看到任何崩溃w /我们的适配器有光标被撕掉并变为空,但你的里程可能会有所不同..(这是更多关于使用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
   }
}