使用CursorLoader和FilterQueryProvider进行ListView过滤? [英] ListView filtering with CursorLoader AND FilterQueryProvider?
问题描述
在我们的项目中,我们与列表打交道,并在过去将其与以下模式"一起使用:
In our Project we deal a lot with Lists and used it in the past with the following "pattern":
ListView在一个Fragment中,在onActivityCreated中初始化,在该处我们首先启动CursorLoaders,然后在onFinish swapCusor中到达ListAdapter.然后,我们使用filterQueryProvider实现了搜索功能,该功能仅返回带有contentResolver.query(...)的游标.如果我在选择列表中的某项时进行了一些方向更改,则在很多情况下(不是正常),我会收到以下错误消息:
ListView is in a Fragment, gets initialized in onActivityCreated where we first start CursorLoaders and then in onFinish swapCusor to the ListAdapter. We then implemented a search functionality using the filterQueryProvider which just returns a cursor with contentResolver.query(...). If i have done some orientation changes while something in the list was selected i got the following error in many cases (not regularly):
android.database.StaleDataException: Attempted to access a cursor after it has been closed.
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1967)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1992)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3378)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.access$700(ActivityThread.java:127)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1162)
12-05 10:36:59.531: E/ACRA(12079): at android.os.Handler.dispatchMessage(Handler.java:99)
12-05 10:36:59.531: E/ACRA(12079): at android.os.Looper.loop(Looper.java:137)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.main(ActivityThread.java:4448)
12-05 10:36:59.531: E/ACRA(12079): at java.lang.reflect.Method.invokeNative(Native Method)
12-05 10:36:59.531: E/ACRA(12079): at java.lang.reflect.Method.invoke(Method.java:511)
12-05 10:36:59.531: E/ACRA(12079): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:823)
12-05 10:36:59.531: E/ACRA(12079): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:590)
12-05 10:36:59.531: E/ACRA(12079): at dalvik.system.NativeStart.main(Native Method)
12-05 10:36:59.531: E/ACRA(12079): Caused by: android.database.StaleDataException: Attempted to access a cursor after it has been closed.
12-05 10:36:59.531: E/ACRA(12079): at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:75)
12-05 10:36:59.531: E/ACRA(12079): at android.database.BulkCursorToCursorAdaptor.getColumnNames(BulkCursorToCursorAdaptor.java:170)
12-05 10:36:59.531: E/ACRA(12079): at android.database.AbstractCursor.getColumnIndex(AbstractCursor.java:248)
12-05 10:36:59.531: E/ACRA(12079): at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:266)
12-05 10:36:59.531: E/ACRA(12079): at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:78)
12-05 10:36:59.531: E/ACRA(12079): at android.support.v4.widget.CursorAdapter.swapCursor(CursorAdapter.java:344)
12-05 10:36:59.531: E/ACRA(12079): at
在方向更改后在onLoadFinished中使用swapCursor时就是这种情况.
this is case when using swapCursor in onLoadFinished after the orientation Change.
我现在使用带有参数的restartLoader并使用带有限制的附加路径的Contacts.CONTENT_FILTER_URI来重新实现过滤器功能,然后在onLoadFinished中交换此游标,因此我删除了filterQueryProvider,看起来运行良好.
I now reimplemented the filter functionality using restartLoader with arguments and using the Contacts.CONTENT_FILTER_URI with appended path which is the constraint and then swapping this cursor in onLoadFinished, so i removed the filterQueryProvider, which looks to work fine.
问题是:是否有可能(或很好的实践)最初使用CursorLoader和filterQueryProvider?还是我必须决定?因为我只使用filterQueryProvider并使用约束为null进行过滤时会达到相同的结果,这只会加载我所需的联系人列表,然后进行过滤.
The question is: Is there a possibility (or good practise) to use CursorLoader initially AND the filterQueryProvider? or do i have to decide? because the same result i reach when just using the filterQueryProvider and just do the filtering with constraint null which just loads my required contactlist and does the filtering afterwards.
有什么建议吗?我没有通过Google找到关于此的mathinc信息;)
Any recommendations? I did not found mathinc information on this via google ;)
这是我当前的LoaderCallbacks实现btw:
this is my current LoaderCallbacks implementation btw:
private LoaderManager.LoaderCallbacks<Cursor> phoneBookContactsLoaderCallback = new LoaderManager.LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// if(constraint != null && constraint.length() > 0) {
// selection = Contacts.DISPLAY_NAME + " LIKE ?";
// selectionArgs = new String [] {"%" + constraint + "%"};
// }
numLoaderManagersRunning++;
String constraint = null;
if(args != null){
constraint = args.getString(CONSTRAINT);
}
Uri uri = null;
if(constraint!= null && !constraint.isEmpty()){
uri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, constraint);
} else {
uri = Contacts.CONTENT_URI;
}
return new CursorLoader(getActivity(), uri , PROJECTION_PHONEBOOK_CONTACTS,
null, null, Contacts.DISPLAY_NAME + " COLLATE NOCASE ASC");
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
Logger.e(TAG, "Load finished ");
// phoneBookContactsCursorAdapter.swapCursor(new MatrixCursor(new String [] { Contacts._ID,
// Contacts.DISPLAY_NAME, Contacts.PHOTO_ID }));
phoneBookContactsCursorAdapter.swapCursor(data);
if (actualMultiFilterListener != null){
actualMultiFilterListener.onFilterComplete(data.getCount());
}
//filterList("");
numLoaderManagersRunning--;
if (numLoaderManagersRunning <= 0) {
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// phoneBookContactsCursorAdapter.swapCursor(null);
Logger.e(TAG, "Load resetted ");
}
};
推荐答案
有点晚了,但是我遇到了完全相同的问题,评论也没有很好的解释性.对于那些面临问题的人,这里是解决方案:
A little bit late but I have faced exact same problem and comments were not well explanatory. For those who faces the problem here is the solution:
停止使用FilterQueryProvider.CursorLoader也可以替代:使用过滤器重新启动它,一切都会好起来的." (什么意思;
而不是这样做:
@Override
public Cursor runQuery(CharSequence listId) {
return mDb.getContacts(listId);
}// DO NOT set direct database query, has no observation at all.
或
@Override
public Cursor runQuery(CharSequence listId) {
return getContentManager.query(....,new String[]{listId}...
}// DO NOT return content manager result, forgets observers.
或
@Override
public Cursor runQuery(CharSequence listId) {
Bundle bundle = new Bundle();
bundle.putCharSequence("selected", listId);
getLoaderManager().restartLoader(CURSOR_LOADER_CONTACTS, bundle, MainActivity.this);
return null;
}// DO NOT restart the cursor loader with new info, screws observers.
与mContactAdapter.getFilter().filter(id+"");
(在应用过滤器时)组合
执行以下操作:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case CURSOR_LOADER_CONTACTS:
long mListId = 0;
if (args != null) {
mListId = args.getLong(CONTACT_FILTER);
}
return new CursorLoader(this, ContentProvider.CONTACT_DISPLAY_URI, null, ContactTable.COLUMN_GROUP_ID+"=?", new String[]{id+""}, null);
} //Apply filter here with new info comes from 'restartLoader'
return null;
}
与getLoaderManager().restartLoader(MainActivity.CURSOR_LOADER_CONTACTS, bundle, MainActivity.this);
假设MainActivity.this
实现LoaderManager.LoaderCallbacks<Cursor>
这篇关于使用CursorLoader和FilterQueryProvider进行ListView过滤?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!