Как я могу улучшить (воспринимаемую) скорость при создании сложного списка ListView с помощью Android?

У меня есть приложение, использующее ListView в качестве основного экрана. Каждая строка отображает некоторый текст, флажок и изображения в соответствии с данными, и, поскольку вы не можете сделать это со стандартным ListAdapter, я создал свой собственный.

Каждый раз, когда происходит изменение (добавление/удаление строки, проверка подсказки, навигация и т. д.) в данных списка, я обновляю отображение списка, используя этот метод:

public void refreshList()
{
    // fetch the new items
    ItemDbHelper items = new ItemDbHelper(this);
    Cursor item_cursor = items.fetchItemForCurrentView(this.current_context_filter);

    // do not use "start managing cursor" here or resume() won't work
    // anymore since the cursor will be closed despite we still need it

    // set the welcome message if no items to display
    if (item_cursor.getCount() == 0)
    {
        TextView message = (TextView) this.findViewById(R.id.home_message);
        message.setVisibility(View.VISIBLE);
    }

    ListView list = this.task_list;
    ItemListAdapter item_cursor_adater = (ItemListAdapter) list.getAdapter();

    // close the old cursor manually and replace it with the new one
    item_cursor_adater.getCursor().close();
    item_cursor_adater.changeCursor(item_cursor);
    // reset some cache data in the adapter
    item_cursor_adater.reset();
    // tell the list to refresh
    item_cursor_adater.notifyDataSetChanged();

    // to easy navigation, we set the focus the last selected item
    // set the last modified item as selected
    int selected_index = this.getItemPositionFromId(list, 
                                                    this.getCurrentContextFilter()
                                                        .getSelectedTaskId());

    list.setSelection(selected_index);
}

Некоторые факты :

  • items.fetchItemForCurrentView() запускает очень тяжелый SQL-запрос

  • this.getItemPositionFromId() выполняет цикл по всему ListView построчно, чтобы найти индекс строки с заданным идентификатором.

  • item_cursor_adapter расширяет SimpleCursorAdapter и переопределяет

    public View getView (int position, View convertView, ViewGroup parent)

Это довольно тяжелый метод.

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

Есть ли у вас какие-либо предложения о том, как это можно улучшить?

Некоторые идеи :

  • Используйте потоки для загрузки данных. Но как потом подкормить список? Как сделать так, чтобы это не мешало на экране?
  • Сделайте повторное использование некоторых объектов/используйте кеш, о котором я не подумал.
  • Найдите способ обновить список без перезагрузки ВСЕХ
  • Измените мою реализацию адаптера курсора. Может быть, расширяет более эффективного родителя или использует что-то лучше, чем getView?

person e-satis    schedule 22.08.2009    source источник


Ответы (2)


Вы можете избавиться от всего этого кода и просто вызвать requery() на Cursor. Как следует из названия, он повторно запускает запрос, который сгенерировал Cursor в первую очередь. Это подхватит изменения данных и уведомит ваш адаптер списка об этих изменениях. Ваш адаптер списка обновит экран для видимых строк.

Для SimpleCursorAdapter либо переопределите newView()/bindView(), либо используйте ViewBinder, либо используйте setViewValue() и аналог, как описано в документация. Вы можете переопределить getView(), но тогда вам придется выполнять собственные операции по повторному использованию строк.

person CommonsWare    schedule 22.08.2009
comment
Привет, спасибо за newView()/bindView(), попробую. Я забыл сказать, что не могу использовать requery(), потому что каждый раз генерируется совершенно другой SQL-запрос. - person e-satis; 23.08.2009

использовать адаптер курсора вместо базового адаптера и адаптера массива

person kranti    schedule 05.06.2013