【问题标题】:Content Provider w/ Cursor - Gets Killed (how to notify client)带光标的内容提供者 - 被杀死(如何通知客户端)
【发布时间】:2012-09-10 14:02:02
【问题描述】:

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

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

在provider中,游标返回一个表,每个intent服务请求填充对应的表,并触发一个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)

有什么方法可以从调用应用程序获取此通知?

【问题讨论】:

    标签: android cursor android-contentprovider


    【解决方案1】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-12
      • 2020-11-20
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      相关资源
      最近更新 更多