Заполните виджеты из курсора в onLoadFinished ()

Я хочу знать, как использоватьCursorLoader заполнить виджеты на экране. Все примеры в сети только для использования адаптера, и это прекрасно работает. Что мне нужно, так это надежный способ обновления представлений на моем экране из курсора и потока пользовательского интерфейса, без периодического сбоя из-заStaleDataException или курсор был деактивирован внезапно. Вот мой текущий подход, но я все еще получаю некоторые отчеты о сбоях от пользователей.

<code>@Override
    public Loader<Cursor> onCreateLoader(int id, Bundle arg1) {
        CursorLoader loader = null;

        switch (id) {
            case LOADER_ID_DATA:
                loader = new CursorLoader(...);
                break;
        }

        return loader;
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, final Cursor cursor) {
        handler.post(new Runnable() {

            @Override
            public void run() {
                if (getActivity() == null)
                    return;

                updateView(cursor);
            }
        });
    }

    @Override
    public void onLoaderReset(Loader<Cursor> arg0) {
    }
</code>

Одним из решений было бы получить все поля курсора непосредственно внутри onLoadFinished и передать их все обработчику для заполнения виджетов в потоке пользовательского интерфейса. Но это ужасно, потому что у меня может быть много значений в курсоре. Я хотел бы найти надежный безотказный способ справиться со всем этим.

 CommonsWare11 апр. 2012 г., 14:33
"Одним из решений было бы получить все поля курсора непосредственно внутри onLoadFinished и передать их все обработчику для заполнения виджетов в потоке пользовательского интерфейса" -onLoadFinished() вызывается в главном потоке приложения.
 CommonsWare11 апр. 2012 г., 14:45
Примеры документации (например, вызовswapCursor() наCursorAdapter) требует, чтобы он вызывался в главном потоке приложения. Я написал проекты, которые используютLoader и может обновлять интерфейс напрямую изonLoadFinished(), такие как: Github.com / commonsguy / CW-advandroid / дерево / мастер / Погрузчики / .... И в документации прямо говорится: «Подклассы Loader (такие как AsyncTaskLoader) будут часто выполнять свою работу в отдельном потоке, но при доставке результатов это также должно быть сделано в основном потоке».
 Catalin Morosan11 апр. 2012 г., 14:39
@ CommonsWare Насколько я знаю, onLoadFinished не вызывается в главном потоке пользовательского интерфейса. Если вы посмотрите, например, на исходный код android-protips_location, написанный Рето Мейером, он использует обработчик для заполнения значений в виджетах. И его комментарий выше onLoadFinished () состоит в том, что он планирует обновление в главном потоке приложения.
 Dori17 апр. 2012 г., 13:23
Это странно, потому что в книге про Рето про андроид 4 он говорит то же самое - я сам не видел в документации по Android и не сталкивался с какими-либо проблемами, связанными с темой пользовательского интерфейса здесь ...
 CommonsWare15 июл. 2012 г., 17:33
@ AlexLockwood: Как указано в принятом ответе, единственная конкретная реализацияLoader в Android SDK - и все остальное, что наследуется отAsyncTaskLoader - звонкиonLoadFinished() в основной ветке приложения. Reto является верным, поскольку в документации не указано, чтоonLoadFinished() вызывается в главном потоке приложений. Но документация почтиникогд указывает для данного метода, когда он вызывается в основном потоке приложения, так что это не является необычным.

Ответы на вопрос(1)

Решение Вопроса

SimonVT а такжеreadme помог мне понять суть.

Ничто не говорит о том, чтоonLoadFinished будет вызываться в потоке пользовательского интерфейса, поэтому теоретически вы должны использоватьHandler как посоветовано в книге Рето. Однако при использованииCursorLoader (что является наиболее распространенным вариантом использования), вы можете в значительной степени гарантировать, чтоonLoadFinished будет вызываться в потоке пользовательского интерфейса.

 SimonVT18 мая 2012 г., 14:09
Причина "в значительной степени" заключается в том, что CursorLoader использует AsyncTask для выполнения своей фоновой работы, которая использует статический обработчик для отправки сообщений и, в конечном счете, вызова onLoadFinished. Если вы вызываете LoaderManager.initLoader (...) из основного потока, обработчик гарантированно будет также присоединен к основному потоку. Чтобы этот обработчик не был присоединен к основному потоку, вам нужно создать поток с лупером и запустить там загрузчик.

Ваш ответ на вопрос