Android CursorAdapters, ListViews и фоновые потоки - PullRequest
3 голосов
/ 27 августа 2009

В этом приложении, над которым я работал, есть базы данных с несколькими мегабайтами данных, которые нужно просеять. Многие действия - это просто ListViews, спускающиеся по разным уровням данных в базах данных, пока мы не достигнем «документов», то есть просто HTML, который нужно извлечь из БД и показать на телефоне. Проблема, с которой я сталкиваюсь, заключается в том, что некоторые из этих действий должны иметь возможность поиска в базах данных путем захвата нажатий клавиш и повторного выполнения запроса с «like% blah%» в нем. Это работает достаточно быстро, за исключением случаев, когда пользователь впервые загружает данные и когда пользователь впервые нажимает клавишу. Я использую ResourceCursorAdapter и создаю курсор в фоновом потоке, но для того, чтобы сделать listAdapter.changeCursor (), мне нужно использовать обработчик, чтобы опубликовать его в основном потоке пользовательского интерфейса. Этот конкретный вызов затем останавливает поток пользовательского интерфейса достаточно долго , чтобы вызвать страшный диалог ANR. Мне интересно, как я могу полностью разгрузить это в фоновом потоке, чтобы пользовательский интерфейс оставался отзывчивым, и у нас не появлялись диалоги ANR.

Просто для полного раскрытия я изначально возвращал ArrayList объектов пользовательской модели и использовал ArrayAdapter, но (по понятным причинам) клиент указал, что это плохое управление памятью, и я все равно не был доволен производительностью. Я действительно хотел бы избежать решения, где я генерирую огромные списки объектов, а затем делаю listAdapter.notifyDataSetChanged / Invalidated ()

Вот код вопроса:

private Runnable filterDrugListRunnable = new Runnable() {
    public void run() {
        if (filterLock.tryLock() == false) return;

        cur = ActivityUtils.getIndexItemCursor(DrugListActivity.this);

        if (cur == null || forceRefresh == true) {
            cur = docDb.getItemCursor(selectedIndex.getIndexId(), filter);
            ActivityUtils.setIndexItemCursor(DrugListActivity.this, cur);
            forceRefresh = false;
        }

        updateHandler.post(new Runnable() {
           public void run() {
               listAdapter.changeCursor(cur);
           }
        });

        filterLock.unlock();

        updateHandler.post(hideProgressRunnable);
        updateHandler.post(updateListRunnable);
    }
};

Ответы [ 2 ]

1 голос
/ 27 августа 2009

Мне трудно поверить, что одного listAdapter.changeCursor() потребуется достаточно времени, чтобы вызвать ANR, при условии, что вы создали Cursor в фоновом потоке. Просто не должно быть так много работы, которая должна случиться, чтобы перекрасить горстку строк списка. Я бы еще раз проверил, насколько ограничена ваша работа с Handler. Возможно, стоит рассмотреть вопрос об использовании AsyncTask, который облегчает отделение фоновой работы (doInBackground()) от постобработки потока в пользовательском интерфейсе (onPostExecute()).

Вы можете попробовать просто заменить адаптер сразу, позвонив setAdapter() снова с новым Cursor, завернутым в новый адаптер.

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

0 голосов
/ 15 июня 2010

Только что опубликовал ответ здесь: Android: Обновление списка после того, как Thread загружает данные из сети

Short: метод AsyncTask onProgressUpdate может касаться представления: http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...