2013-05-06 2 views
2

Я загружаю некоторые результаты из базы данных с помощью loaderManager. К сожалению, следующий код производит StaleDataException после поворота устройства:Слияние курсоров во время onLoadFinished() вызывает StaleDataException после вращения

@Override 
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) 
{ 
    // If we've returned results, then pass them and the webSearches cursor along to be displayed 
    if(cursor.moveToFirst()) 
    { 
     // Get a cursor containing additional web searches and merge it at the end of the results cursor 
     MatrixCursor searchesCursor = getWebSearchesCursor(searchTerm, false); 
     Cursor[] cursors = { cursor, searchesCursor }; 
     // TODO: Figure out why merging cursors here causes staledataexception after rotation 
     Cursor results = new MergeCursor(cursors); 
     // Display the cursor in the ListView 
     adapter.changeCursor(results); 
    } 
    // If no results were returned, then return suggestions for web searches 
    else 
    { 
     // Get a cursor containing additional web searches 
     MatrixCursor noResults = getWebSearchesCursor(searchTerm, true); 
     adapter.changeCursor(noResults);  
    } 

    // Show the listView and hide the progress spinner 
    toggleListView(SHOW); 
} 

Вызова getWebSearchesCursor() возвращает MatrixCursor с некоторым дополнительным поиском подсказками, чтобы сопровождать все возвращенные результаты. Я обнаружил, что изменение adapter.changeCursor (results) to adapter.changeCursor (cursor) исправляет ошибку, поэтому похоже, что слияние MatrixCursor с возвращенным курсором вызывает ошибку.

Мой вопрос: почему?

Если какие-либо результаты возвращены, я хотел бы иметь возможность добавлять дополнительные элементы в возвращаемый курсор, чтобы пользователь мог выполнять поиск на нескольких веб-сайтах. Есть ли лучший способ объединить курсоры, чтобы я не получил это исключение после ротации?

ответ

1

Эта проблема возникла еще пару дней назад, и мне посчастливилось споткнуться о решении.

Я узнал, что должен был использовать swapCursor() вместо changeCursor(). According to the Android docs:

Обмен в новом курсоре, возвращающий старый курсор. В отличие от changeCursor (Cursor), возвращенный старый курсор не закрыт.

...

Если данный новый Cursor тот же экземпляр ранее установлен курсор, нуль также возвращается.

Эта последняя часть, казалось, была ключом. Ошибка, упомянутая в вопросе выше, может быть прослежена до того, как CursorAdapter захлестнул объединенный курсор, потому что он был закрыт, когда он попытался перерисовать фрагмент после поворота. Используя вместо этого swapCursor(), CursorAdapter смог повторно использовать «старый» объединенный курсор вместо того, чтобы подвергать сомнению его достоверность и бросать исключение StaleDataException.

Я делаю некоторые предположения здесь; возможно, кто-то более осведомленный во внутренних разработках Android может подтвердить или опровергнуть мои рассуждения.

1

Если вы начали использовать swapCursor() вместо changeCursor() везде, то, надеюсь, вы также начали обрабатывать закрытие курсора в этих местах.

changeCursor() закроет старый курсор, это намеренно и работает безупречно, когда вы просто используете курсор, предоставленный onLoadFinished(). Это делается так, поэтому вам не нужно беспокоиться о его закрытии.

При повороте устройства система Android будет проверять, что курсор, который он отправил в последний раз, еще не закрыт и отправляет его снова, а не тратит ресурсы на создание нового. Ваш код обертывает этот курсор в новом экземпляреMergeCursor, который передается в changeCursor(), который видит, что это не тот объект, который он получил раньше, и решает закрыть старый экземпляр. Поскольку MergeCursor только обертывает курсоры, которые вы передаете, вместо того, чтобы копировать данные в них, ваш новый экземпляр теперь содержит (по крайней мере) один закрытый курсор.

Для правильной работы с этим вам необходимо написать собственный код, который проверяет, находится ли курсор, который вы получаете через onLoadFinished(), тот же, что у вас есть в текущем экземпляре MergeCursor, и только закрывайте существующий экземпляр, если вы получение нового курсора. Конечно, вам также нужно будет отслеживать другие курсоры, завернутые в один и тот же экземпляр MergeCursor.

 Смежные вопросы

  • Нет связанных вопросов^_^