Как загрузить Listview «плавно» в android

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

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

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

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); } 

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

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

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)

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

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

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

Я столкнулся с этой проблемой, но в моем случае я использовал потоки для получения внешних изображений. Важно, чтобы текущий исполняемый поток не менял 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(); 

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

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

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