Intereting Posts
Google в покупке и взломе приложений Проблемы с Android при воспроизведении аудиофайла Android: BitmapFactory.decodeByteArray дает пикселированное растровое изображение Как проверить предыдущее значение в android viewflipper Почему мое меню редактирования / вставки EditText находится под EditText? Как изменить всплывающее окно z-порядка? Синхронизация нескольких поставщиков с одним SyncAdapter Как проверить JUnit IntentService Как обрезать изображения без использования намерений в Android Как я могу эмулировать высоту кнопок (тень) в Android API ниже 21? Анимация ViewPager для заполнения экрана в Android Качество видео в Android? Сложная панель инструментов не рушится должным образом при просмотре ресайклера внутри нее Могу ли я передавать различные типы параметров AsyncTask в Android? Использование класса Application для хранения постоянных данных в Android Java.lang.NoSuchMethodError: android.app.ANRAppManager.dumpMessageHistory

Фильтрация ListView с помощью CursorLoader И FilterQueryProvider?

В нашем проекте мы много разбираемся со списками и использовали его в прошлом со следующим «шаблоном»:

ListView находится в фрагменте, получает инициализацию в 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 

Это происходит при использовании swapCursor в onLoadFinished после изменения ориентации.

Я теперь переопределял функциональность фильтра с помощью restartLoader с аргументами и используя Contacts.CONTENT_FILTER_URI с добавленным путем, который является ограничением, а затем заменяет этот курсор на onLoadFinished, поэтому я удалил filterQueryProvider, который выглядит нормально.

Возникает вопрос: есть ли возможность (или хорошая практика) использовать CursorLoader изначально И filterQueryProvider? Или я должен решить? Потому что тот же результат я достигаю, когда просто использую filterQueryProvider, и просто делаю фильтрацию с ограничением null, который просто загружает мой список контактов и выполняет фильтрацию впоследствии.

Есть рекомендации? Я не нашел mathinc информацию об этом через google;)

Это моя текущая реализация 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 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. 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>

    При использовании FilterQueryProvider используйте перезагрузку, вместо initLoader