Состояние гонки с LoaderManager?

Я использую LoaderManager для загрузки курсора списка контактов с моего телефона.

Я буквально использую только приведенный здесь пример кода:

http://developer.android.com/reference/android/app/LoaderManager.html

Мое единственное изменение заключается в том, что вместо того, чтобы использовать его в качестве адаптера для просмотра списка на главном экране, я использовал его в качестве адаптера для AutoCompleteTextView. Моя проблема в том, что когда я быстро меняю текст, либо яростно печатая, либо удерживая кнопку удаления, чтобы удалить все подряд, это приводит к этой ошибке:

01-09 02:36:47.248: E/AndroidRuntime(24231): FATAL EXCEPTION: main
01-09 02:36:47.248: E/AndroidRuntime(24231): android.database.StaleDataException: Attempted to access a cursor after it has been closed.
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.database.BulkCursorToCursorAdaptor.throwIfCursorIsClosed(BulkCursorToCursorAdaptor.java:64)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.database.BulkCursorToCursorAdaptor.getColumnNames(BulkCursorToCursorAdaptor.java:159)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.database.AbstractCursor.getColumnIndex(AbstractCursor.java:283)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:308)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:78)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.widget.CursorAdapter.swapCursor(CursorAdapter.java:338)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.widget.CursorAdapter.changeCursor(CursorAdapter.java:309)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.widget.CursorFilter.publishResults(CursorFilter.java:67)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:282)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.os.Handler.dispatchMessage(Handler.java:99)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.os.Looper.loop(Looper.java:137)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at android.app.ActivityThread.main(ActivityThread.java:5070)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at java.lang.reflect.Method.invokeNative(Native Method)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at java.lang.reflect.Method.invoke(Method.java:511)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
01-09 02:36:47.248: E/AndroidRuntime(24231):    at dalvik.system.NativeStart.main(Native Method)

person David Liu    schedule 09.01.2013    source источник


Ответы (1)


Кажется, что CursorAdapter имеет базовую реализацию getFilter(), которая возвращает текущий курсор после выполнения runQueryOnBackgroundThread(). Это прекрасно работает для исходного примера разработчика Android для LoaderManager, поскольку ListView вообще не использует фильтр. Однако AutoCompleteTextViews используют фильтр, поэтому я, по сути, запускал два асинхронных потока, которые пытались загрузить курсоры, и не был потокобезопасным.

Поскольку фильтр уже обеспечивает ту же функциональность асинхронной загрузки, что и LoaderManager, я просто отказался от LoaderManager и загружаю через фильтр, переопределив CursorAdapter.runQueryOnBackgroundThread().

person David Liu    schedule 10.01.2013
comment
Для тех, кто ищет ответы в будущем, LoaderManager смехотворно устарел в наши дни, поэтому его следует избегать любой ценой. - person David Liu; 30.03.2018