Android: ListView с настраиваемым адаптером ArrayAdapter для длинных списков - проблема синхронизации! - PullRequest
0 голосов
/ 06 мая 2011

Привет всем,

У меня есть этот "результаты поиска" ListView.Результаты поиска могут быть разных «видов» (разные разделы, называйте это).Чтобы отделить «виды», я добавляю строку с заголовком.(Я знаю о расширяемом списке, но не могу использовать его по другим причинам).

В моем getView () я проверяю свойство, и если он установлен, я изменяю цвет фона строки.

Проблема: когда я запускаю запрос, который возвращает всего несколько строк (скажем, 15), все в порядке.Но когда я запускаю другой, который возвращает, скажем, 600 строк, что-то выходит из-под контроля и случайным образом меняет фон с некоторой регулярностью.То же самое происходит, когда я работаю в режиме отладки и останавливаюсь в середине.

Итак, это определенно проблема с синхронизацией.

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

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

Если проблема в клавиатуре, есть ли механизм, чтобы сообщить списку «подождите, пока вещь не закроется» перед началом рендеринга?(Не уверен, что мне это нравится, но это лучше, чем получать милую маленькую радугу ...)

Спасибо!

Llappall

-

Вотадаптер и расположение элементов (ниже):

private class ElementAdapter extends ArrayAdapter<Element> {
  private ArrayList<Element> rows;
  private Element.typeEnum type;

  public ElementAdapter(Context context, int textViewResourceId, ArrayList<Element> rows) {
    super(context, textViewResourceId, rows);
    this.rows = rows;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
      LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      v = vi.inflate(R.layout.element, null);
    }
    Element row = rows.get(position);
    if (row == null) {
      return v;
    }
    v.setTag(row);
    type = row.getType();
    boolean isSectionType = type == Element.typeEnum.DIV118SECTION || type == Element.typeEnum.APPASECT ||
      type == Element.typeEnum.APPBSECT || type == Element.typeEnum.AZSECT;

    TextView title = (TextView) v.findViewById(R.id.title);
    TextView body = (TextView) v.findViewById(R.id.body);
    if (isSectionType) {
      body.setMaxLines(5000);
    }
    title.setText(row.getTitle());
    if (row.getBody() != null) {
      body.setText(row.getBody());
    }
    if (type == Element.typeEnum.SEARCHLISTHEADER) {
      v.setBackgroundColor(Color.rgb(230, 230, 250));
      title.setBackgroundColor(Color.rgb(230, 230, 250));
      body.setBackgroundColor(Color.rgb(230, 230, 250));
      star.setBackgroundColor(Color.rgb(230, 230, 250));
    }
    return v;
  }
}

== ПЛАН ЭЛЕМЕНТОВ ==

<TextView
  android:id="@+id/body"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:maxLines="1"
  style="@style/ListItemSubTitle" />
</LinearLayout>

Ответы [ 2 ]

0 голосов
/ 10 мая 2011

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

    private class ElementAdapter extends ArrayAdapter<Element> {

    public ElementAdapter(Context context, int textViewResourceId, ArrayList<Element> rows) {
        super(context, textViewResourceId, rows);
        this.rows = rows;
    }

    private final ArrayList<Element> rows;

    @Override
    public View getView(final int position, View convertView, final ViewGroup parent) {
        ViewsHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.element, parent, false);
            holder = new ViewsHolder();
            holder.title = (TextView) v.findViewById(R.id.title);
            holder.body = (TextView) v.findViewById(R.id.body);
            convertView.setTag(holder);
        } else {
            holder = (ViewsHolder) convertView.getTag();
        }
        final Element row = rows.get(position);
        final Element.typeEnum type = row.getType();
        if (type.equals(Element.typeEnum.DIV118SECTION) || type.equals(Element.typeEnum.APPASECT) ||
                  type.equals(Element.typeEnum.APPBSECT) || type.equals(Element.typeEnum.AZSECT)) {
            body.setMaxLines(5000);
        }
        holder.title.setText(row.getTitle());
        if (row.getBody() != null) {
            holder.body.setText(row.getBody());
        } else {
            holder.body.setText("");
        }
        if (type == Element.typeEnum.SEARCHLISTHEADER) {
            convertView.setBackgroundColor(Color.rgb(230, 230, 250));
            holder.title.setBackgroundColor(Color.rgb(230, 230, 250));
            holder.body.setBackgroundColor(Color.rgb(230, 230, 250));
            //star.setBackgroundColor(Color.rgb(230, 230, 250)); // Where did that come from?
        }
        return convertView;
      }

    private final class ViewsHolder {
        public TextView title;
        public TextView body;
    }
}

Пара замечаний по оригинальному коду:

if (row == null) { return v; }

неправильно. Вы не должны иметь никаких нулевых элементов в вашем списке для любой позиции в списке. Даже если у вас есть, вы не должны просто бросить случайное представление для строки. То, что вы здесь делаете, возвращает «v», которое вполне может быть (и, вероятно, будет) какой-то переработанной старой строкой, которая по-прежнему отображает старые данные, и это вводит пользователя в заблуждение. Я сделал предположение, что у вас не будет пустых элементов при написании кода.

if (row.getBody() != null) {
  body.setText(row.getBody());
}

Почти нормально, но, опять же, если вы повторно используете convertView (который является какой-то случайной предыдущей строкой, которая больше не отображается), то, если body на самом деле имеет значение null, вы просто будете отображать старые данные, что снова приведет в замешательство пользователь. Если body имеет значение null, просто установите пустую строку.

P.S. Я рекомендую вам ознакомиться с советами и рекомендациями по работе с ListView: Мир ListView

0 голосов
/ 06 мая 2011

Было бы намного проще, если бы вы разместили здесь метод getView ().Из того, что я могу сказать, вы можете использовать переработанные представления неправильно.Проверьте, не изменился ли фон на что-либо, если свойство не установлено.Например:

if (peoperty.isSet()) {
  changeBackGround();
}

Само по себе будет неправильно, если вы повторно используете convertView, так как фон будет оставаться таким же цветом, каким он был, когда этот вид использовался для другой строки.

должно быть что-то вроде:

if (peoperty.isSet()) {
  changeBackGround();
} else {
  changeBackgroundToSomethingNeutral()
}
...