Как запланировать тяжелую работу для последующего отображения в списках просмотра? - PullRequest
5 голосов
/ 27 марта 2010

У меня есть список с 200 предметами. Я использую пользовательский вид для каждой строки. Существует код, который требует некоторого времени для расчета, и из-за этого список зависает при прокрутке и загружается медленно (2-3 секунды).

Я создал подкласс SimpleCursorAdapter и использую Filterable и SectionIndexer.

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

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

Ответы [ 2 ]

2 голосов
/ 27 марта 2010

Поскольку Android-интерфейс Android является однопоточным, он будет заблокирован при выполнении длительной операции.

Вы можете выполнять обычные потоки Java и иметь Handler () в основном классе пользовательского интерфейса, в который вы можете передавать информацию. Но ..

Самый простой способ - создать AsyncTask (). Это Java-темы с небольшим изменением. Они могут выполнять операции пользовательского интерфейса до / после основного расчета. Так, например:

 private class AndroidThread extends AsyncTask {
      protected Object doInBackground(Object... params) {
           return result;
      }

      protected void onPostExecute(Object result) {
           // do things here with the result of the doInBackground function
           // Like: "UiElement"."performTask(result)"
      }
 }

Для получения дополнительной информации об AsyncTask см.

1 голос
/ 27 марта 2010

Хм, интересный вопрос.Вот несколько быстрых мыслей:

1) Поместите значения, которые можно получить напрямую, то есть имя записи, как вы ее положили, прямо в список.Оставьте значения по умолчанию, такие как «Загрузка ...», для всего, что может занять некоторое время для вычисления.

2) Создайте второй поток для выполнения вычислений, но убедитесь, что он не рассчитывается все использовать прослушиватель ListView onScrollStateChanged.Это позволяет выполнять фоновую работу только в том случае, если список либо простаивает, либо медленно прокручивается с помощью сенсорной прокрутки.Другими словами, не беспокойтесь, когда он находится в режиме «сбрасывания», поскольку строки должны были пройти задолго до завершения вычислений.

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

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

Я надеюсь, что эти идеи помогут немного!


В ответ на комментарий: Предполагая, что вы спрашиваете, когда строка видна, вы можете сделать это, реализовав ListView.OnScrollListener.Я черпал вдохновение из ApiDemos List13, но вот соответствующие кусочки кода:

public class YourClass extends ListActivity implements ListView.OnScrollListener {
    public void onCreate(Bundle sIS){
        (...)
        // Note, you may have to write your own list adapter, extending BaseAdapter
        // See List13 in Api Demos for an example if you're not sure how to do that
        setListAdapter(yourImageAdapter); 
        getListView().setOnScrollListener(this);
    }

    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
            int totalItemCount) {
        Log.d(LOG_TAG, "onScroll, firstVisibleItem = " + firstVisibleItem +
                ", visibleItemCount = " + visibleItemCount
                + ", totalItemCount = " + totalItemCount);
    }

    public void onScrollStateChanged(AbsListView view, int scrollState) {
        Log.d(LOG_TAG, "onScrollStateChanged called, scrollState = " + scrollState);
        switch (scrollState) {
        case OnScrollListener.SCROLL_STATE_IDLE:
            int first = view.getFirstVisiblePosition();
            int count = view.getChildCount();

            Log.d(LOG_TAG, "first = " + first + ", count = " + count);

            break;
        case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
            //Scrolling with the finger touching the screen
            break;

        case OnScrollListener.SCROLL_STATE_FLING:
            // User 'threw' the list up or down and it's scrolling rapidly
            break;
        }
    }
}

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

Еще один момент, касающийся BaseAdapter: я не пробовал использовать какой-либо другой вид адаптера списка, поэтому, возможно, он одинаков со всеми из них, но одна очень полезная вещь с BaseAdapter - это то, что он позволяет вам обрабатывать «инфляцию» каждой строки в отдельности.Каждый раз, когда список собирается отобразить новую строку, вызывается getView.Вы можете поместить туда собственный код, чтобы сделать такие вещи, как «Загрузка ...», если информация еще не рассчитана, или на самом деле отобразить ее, если она была.

Кстати, что вы на самом делевычисление в этом списке, что занимает так много времени?

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