android - 使用 CursorLoader 和 FilterQueryProvider 过滤 ListView?

标签 android list listview filter android-cursorloader

在我们的项目中,我们经常处理列表,并在过去通过以下“模式”使用它:

ListView 在 Fragment 中,在 onActivityCreated 中初始化,我们首先启动 CursorLoaders,然后在 onFinish swapCusor 中初始化到 ListAdapter。然后我们使用 filterQueryProvider 实现了一个搜索功能,它只返回一个带有 contentResolver.query(...) 的游标。如果我在选择列表中的某些内容时做了一些方向更改,我在许多情况下(不经常)会收到以下错误:

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 时的情况。

我现在使用带参数的 restartLoader 并使用 Contacts.CONTENT_FILTER_URI 和作为约束的附加路径重新实现过滤器功能,然后在 onLoadFinished 中交换此光标,所以我删除了 filterQueryProvider,它看起来工作正常。

问题是:最初是否有可能(或好的做法)使用 CursorLoader 和 filterQueryProvider?还是我必须决定?因为我在使用 filterQueryProvider 时得到了相同的结果,并且只使用约束 null 进行过滤,它只加载我需要的联系人列表并在之后进行过滤。

有什么建议吗?我没有通过谷歌找到这方面的数学信息;)

顺便说一句,这是我当前的 LoaderCallbacks 实现:

 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 ");
        }
    };

最佳答案

当使用 FilterQueryProvider 时使用 restartLoader 而不是 initLoader

关于android - 使用 CursorLoader 和 FilterQueryProvider 过滤 ListView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20399284/

相关文章:

android - 如何在Android中实现图像失真效果

android - 设置 Spinner 适配器然后更改 EditText 输入类型

Python:根据替换字典/替换映射替换字符串列表中的匹配项

c# - 限制 WPF ListView 中 TextBlock 的宽度

java - Android TodoApp 与 ListView - 列表不显示

android - Gridview 中的复选框未在 setSelection() 上被选中

java - 抓取图片在ImageView上显示,并保存在不同序列号的SD卡中

Python,数据帧: Duplicating rows according to the number of items in a list and ranking the resulted rows

python - 以 Pythonic 方式将项目添加到列表

c# - DataTemplate 中带有 DoubleAnimation 的 Storyboard