使用 CursorLoader 和 FilterQueryProvider 过滤 ListView?

Den*_*989 4 android listview list filter android-cursorloader

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

ListView 位于 Fragment 中,在 onActivityCreated 中初始化,我们首先启动 CursorLoaders,然后在 onFinish 中将 Cusor 交换到 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 
Run Code Online (Sandbox Code Playgroud)

这是在方向更改后在 onLoadFinished 中使用 swapCursor 时的情况。

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

问题是:是否有可能(或好的实践)最初使用 CursorLoader 和 filterQueryProvider?或者我必须决定?因为当我仅使用 filterQueryProvider 并使用约束 null 进行过滤时,我会得到相同的结果,它只会加载我所需的联系人列表,然后进行过滤。

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

顺便说一句,这是我当前的 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 ");
        }
    };
Run Code Online (Sandbox Code Playgroud)

psk*_*ink 5

使用 FilterQueryProvider 时使用 restartLoader 而不是 initLoader