Как загрузить Listview "плавно" в android
Я загружаю данные из Cursor в listview, но мой Listview действительно не отображается "плавным". Данные меняются при перетаскивании вверх и вниз на панели scollbar в моем ListView. И некоторые элементы выглядят как дублированный дисплей в моем списке.
Я hava "сложный ListView" (два textview, oneviewview). Поэтому я использовал newView(), bindView() для отображения данных. Кто-нибудь может мне помочь?
Ответы
Ответ 1
Я расскажу вам, как получить такую проблему, которая у вас есть. Возможно, это поможет вам.
Итак, в адаптере списка у вас есть такой код:
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);
}
у вас будет текущее поведение приложения с дублированием элемента списка.
Возможно, это поможет.
Ответ 2
ListView - хитрый зверь.
Второй вопрос: вы видите дубликаты, потому что ListView повторно использует Views через convertView, но вы не следите за reset всеми аспектами преобразованного представления. Убедитесь, что путь кода для 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 techtalk показывает производительность ListView здесь: http://code.google.com/events/io/sessions/TurboChargeUiAndroidFast.html
Из своего разговора и в порядке важности из моего собственного опыта,
- Использовать convertView
- Если у вас есть изображения, не масштабируйте свои изображения "на лету". Используйте Bitmap.createScaledBitmap для создания масштабированного растрового изображения и поместите его в свои представления.
- Используйте ViewHolder, поэтому вам не нужно каждый раз называть группу findViewByIds()
- Уменьшить сложность просмотров в списке. Чем меньше подпунктов, тем лучше. RelativeLayout намного лучше, чем, скажем, LinearLayout. И обязательно используйте, если вы реализуете пользовательские представления.
Ответ 3
Я тоже сталкиваюсь с этой проблемой, но в моем случае я использовал потоки для получения внешних изображений. Важно, чтобы текущий исполняемый поток не менял 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();
Можно также отменить текущий поток, если их представление будет повторно использовано (как описано здесь), но я решил против этого, потому что хочу для заполнения моего кеша для последующего повторного использования.
Ответ 4
Только один совет: НИКОГДА не используйте прозрачный фон макета элемента - он значительно замедляет производительность.
Ответ 5
Вы можете увидеть повторяющийся текст в нескольких строках, если вы обработаете его не так. В последнее время я немного поболтал об этом - см. здесь. Помимо этого вы можете взглянуть на оптимизацию производительности ListView. Вообще это из-за повторного использования вида, и я видел это несколько раз уже.