Как загрузить Listview «плавно» в Android - PullRequest
11 голосов
/ 24 августа 2009

Я загружаю данные из Cursor в listview, но мой Listview не совсем отображает «smooth». Данные меняются, когда я перетаскиваю вверх и вниз по полосе прокрутки в моем ListView. И некоторые элементы выглядят как дубликаты в моем списке. У меня есть «сложный ListView» (два textview, один imageview), поэтому я использовал newView (), bindView () для отображения данных. Кто-нибудь может мне помочь?

Ответы [ 5 ]

11 голосов
/ 24 августа 2009

Я опишу вам, как получить такую ​​проблему, которая у вас есть. Возможно, это поможет вам.

Итак, в списке адаптеров у вас есть такой код:

public View getView(int position, View contentView, ViewGroup arg2)
    {
        ViewHolder holder;

        if (contentView == null) {
            holder = new ViewHolder();
            contentView = inflater.inflate(R.layout.my_magic_list,null);
            holder.label = (TextView) contentView.findViewById(R.id.label);
            contentView.setTag(holder);
        } else {
            holder = (ViewHolder) contentView.getTag();
        }

        holder.label.setText(getLabel());

        return contentView;
    }

Как видите, мы устанавливаем значение элемента списка только после того, как мы получили владельца.

Но если вы переместите код в приведенное выше выражение if:

holder.label.setText(getLabel());

так будет выглядеть как показано ниже:

if (contentView == null) {
   holder = new ViewHolder();
   contentView = inflater.inflate(R.layout.my_magic_list,null);
   holder.label = (TextView) contentView.findViewById(R.id.label);
   holder.label.setText(getLabel());
   contentView.setTag(holder);
}

у вас будет текущее поведение приложения с дублированием элементов списка.

Возможно, это поможет.

8 голосов
/ 24 августа 2009

ListView - хитрый зверь.

Ваш второй вопрос первым: вы видите дубликаты, потому что ListView повторно использует Views через convertView, но вы не обязательно сбросите все аспекты преобразованного представления. Убедитесь, что путь кода для convertView!=null правильно устанавливает все данные для представления, и все должно работать правильно.

Вы захотите, чтобы ваш getView() метод выглядел примерно так, если вы используете пользовательские представления:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final MyCustomView v = convertView!=null ? (MyCustomView)convertView : new MyCustomView();
    v.setMyData( listAdapter.get(position) );
    return v;
}

Если вы не используете свой собственный вид, просто замените вызов на new MyCustomView() на вызов inflater.inflate(R.layout.my_layout,null)

Что касается вашего первого вопроса, вы можете посмотреть техническую беседу Ромена о производительности ListView здесь: http://code.google.com/events/io/sessions/TurboChargeUiAndroidFast.html

Из его разговора и в порядке важности из моего собственного опыта,

  • Использовать convertView
  • Если у вас есть изображения, не масштабируйте изображения на лету. Используйте Bitmap.createScaledBitmap, чтобы создать масштабированное растровое изображение и поместить его в свои представления
  • Используйте ViewHolder, чтобы вам не приходилось каждый раз вызывать кучу findViewByIds ()
  • Уменьшите сложность представлений в вашем списке. Чем меньше подпредставлений, тем лучше. RelativeLayout намного лучше, чем, скажем, LinearLayout. И обязательно используйте, если вы реализуете пользовательские представления.
1 голос
/ 09 сентября 2012

Только один совет: НИКОГДА не используйте прозрачный фон макета элемента - это сильно снижает производительность

1 голос
/ 30 марта 2011

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

public View getView(int position, View vi, ViewGroup parent) {
ViewHolder holder;
String imageUrl = ...;

if (vi == null) {
    vi = inflater.inflate(R.layout.tweet, null);
    holder = new ViewHolder();
    holder.image = (ImageView) vi.findViewById(R.id.row_img);
    ...
    vi.setTag(holder);
} else {
    holder = (ViewHolder) vi.getTag();      
}
holder.image.setTag(imageUrl);
...
DRAW_MANAGER.fetchDrawableOnThread(imageUrl, holder.image);
}

А затем в потоке извлечения я делаю важную проверку :

final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
     // VERY IMPORTANT CHECK
    if (urlString.equals(url))
        imageView.setImageDrawable((Drawable) message.obj);
};

Thread thread = new Thread() {  

@Override
public void run() {
    Drawable drawable = fetchDrawable(urlString);
    if (drawable != null) {
        Message message = handler.obtainMessage(1, drawable);
        handler.sendMessage(message);
    }
}};
thread.start();

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

0 голосов
/ 05 ноября 2011

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

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