其他分享
首页 > 其他分享> > android – 使用CursorLoader和FilterQueryProvider进行ListView过滤?

android – 使用CursorLoader和FilterQueryProvider进行ListView过滤?

作者:互联网

在我们的项目中,我们对Lists进行了大量处理,并在过去使用了以下“模式”:

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进行过滤,只需加载我所需的联系人列表,然后进行过滤.

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

这是我当前的LoaderCallbacks实现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 onl oadFinished(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 onl oaderReset(Loader<Cursor> loader) {
//            phoneBookContactsCursorAdapter.swapCursor(null);
            Logger.e(TAG, "Load resetted ");
        }
    };

解决方法:

有点迟,但我遇到了完全相同的问题,评论并没有很好地解释.对于那些面临问题的人来说,解决方案是:

“停止使用FilterQueryProvider.CursorLoader也可以替代它:用你的过滤器重启它,你会没事的.” (source)

意思是;

而不是这样做:

@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>

标签:android,filter,listview,android-cursorloader,list
来源: https://codeday.me/bug/20190612/1226998.html