Лучший способ обработки нескольких вызовов getView внутри адаптера
У меня есть ListView
с пользовательским ArrayAdapter
. Каждая строка из этого ListView
имеет значок и некоторый текст. Эти значки загружаются в фоновом режиме, кэшируются, а затем используются обратные вызовы, заменяемые в соответствующем ImageViews
. Логика получения эскиза из кеша или загрузки запускается каждый раз, когда выполняется getView
().
Теперь, по словам Ромена Гая:
"нет абсолютно никакой гарантии на порядок, в котором getView() будет и сколько раз."
Я видел, как это произошло, для строки размером два getView() вызывается шесть раз!
Как мне изменить свой код, чтобы избежать дублирования эскизов-выборки-запросов, а также обрабатывать просмотр?
Спасибо.
Ответы
Ответ 1
Из api.
public abstract View getView (int position, View convertView,
ViewGroup parent)
convertView - старое представление для повторного использования, если это возможно. Примечание. Перед использованием убедитесь, что это представление не имеет значения null и соответствующего типа. Если невозможно преобразовать это представление для отображения правильных данных, этот метод может создать новое представление.
Итак, если getView уже был вызван для этого конкретного индекса, тогда convertView будет объектом View, который был возвращен с первого вызова.
Вы можете сделать что-то вроде.
if(!(convertView instanceof ImageView)){
convertView = new ImageView();
//get image from whereever
} else {} // ImageView already created
Ответ 2
Точно, это может произойти, например, когда у вас есть
android:layout_height="wrap_content"
в вашем определении ListView
. Изменение его на fill_parent/match_parent могло бы избежать этого.
Ответ 3
Я экспериментирую с той же проблемой, я меняю layout_height listView на match_parent, чтобы решить мою проблему.
Ответ 4
Я понимаю, что здесь нужно использовать шаблон дизайна ViewHolder. Простое использование возвращаемого конвертирования может привести к повторному использованию предыдущего представления (с некоторым другим изображением, назначенным в этом случае).
public class ImageAdapter extends ArrayAdapter<String> {
// Image adapter code goes here.
private ViewHolder {
public ImageView imageView;
public String url;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = null;
ViewHolder viewHolder;
String url = getUrl(position);
if (convertView == null) {
// There was no view to recycle. Create a new view.
view = inflator.inflate(R.layout.image_layout, parent, false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) view.findViewById(R.id.image_view);
viewHolder.url = url;
view.setTag(viewHolder);
} else {
// We got a view that can be recycled.
view = convertView;
viewHolder = ((ViewHolder) view.getTag());
if (viewHolder.url.equals(url)) {
// Nothing to do, we have the view with the correct info already.
return view;
}
}
// Do work to set your imageView which can be accessed by viewHolder.imageView
return view;
}
}
Ответ 5
Лучше было бы создать объект с Thumbnail (растровым изображением) и текстом. И прочитайте миниатюру, если она недоступна в объекте.
Ответ 6
Создайте массив объектов ImageView в своем адаптере и кешируйте их при их извлечении (будь то в кеше или в Интернете). Например, в getView, прежде чем вы получите ImageView, проверьте, если он уже находится в вашем локальном массиве, если это так, используйте его, если он не извлекается, после того, как он получил хранилище в вашем локальном массиве ImageView для дальнейшего использования.
Ответ 7
В My Fragment.xml есть ListView, параметр компоновки этого ListView был android: layout_height = "wrap_content" , и этот ListView будет связываться с SimpleCursorAdapter позже. Тогда у меня такая же проблема в ViewBinder вызывается 3 раза. Проблема была решена после того, как я изменил layout_height = "wrap_content" на "95p". Я считаю, что высота "wrap_content" вызывает эту проблему.
Попытка изменить ваш Fragment.xml, и я думаю, что 3-тактная проблема будет больше не существовать.