我在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)
从调用应用程序获取此通知的任何方式?
答案 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
}
}