Universal-Image-Loader: неправильные растровые изображения прикреплены к ImageView
Я оценивал NOSTRA Universal-Image-Loader библиотеку для асинхронно загружать изображения и показывать их в ListView. Пока он работает отлично, за исключением одной проблемы.
Иногда битмапы из кэша памяти привязываются к неправильному ImageViews
при прокрутке списка. После остановки прокрутки правильные изображения прилагаются. Эта ситуация довольно редка, и я не мог найти 100% -ный способ ее воспроизвести. Я снял видео в последний раз, когда это произошло.
Вот код ArticleAdapter
, там могут быть найдены как конфигурация UIL, так и метод bindView()
.
public class ArticleAdapter extends CursorAdapter {
private LayoutInflater inflater;
private ViewHolder holder;
public ArticleAdapter(Context context, Cursor cursor, boolean autoRequery) {
super(context, cursor, autoRequery);
imageLoader = ImageLoader.getInstance();
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.download_progress_thumb)
.cacheInMemory()
.cacheOnDisc()
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
.build();
ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(context)
.threadPriority(Thread.NORM_PRIORITY - 2)
.threadPoolSize(4)
.discCache(new UnlimitedDiscCache(Utils.getCacheDirectory(context)))
.defaultDisplayImageOptions(options)
.build();
imageLoader.init(configuration);
titleIndex = cursor.getColumnIndex(Articles.TITLE);
descriptionIndex = cursor.getColumnIndex(Articles.DESCRIPTION);
isUnreadIndex = cursor.getColumnIndex(Articles.IS_UNREAD);
isNewIndex = cursor.getColumnIndex(Articles.IS_NEW);
urlIndex = cursor.getColumnIndex(Articles.URL);
hostIndex = cursor.getColumnIndex(Articles.HOST);
timeIndex = cursor.getColumnIndex(Articles.PUBLISH_TIME);
bkgUnreadArticle = context.getResources().getColor(R.color.list_bkg_unread_article);
bkgReadArticle = context.getResources().getColor(R.color.list_bkg_read_article);
textUnreadTitle = context.getResources().getColor(R.color.list_text_unread_title);
textReadTitle = context.getResources().getColor(R.color.list_text_read_title);
inflater = LayoutInflater.from(context);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
String date = Utils.format(cursor.getLong(timeIndex), Utils.DATE);
holder = (ViewHolder) view.getTag();
holder.titleView.setText(cursor.getString(titleIndex));
holder.descriptionView.setText(date);
int isNew = cursor.getInt(isNewIndex);
if (isNew == 1)
holder.isNewView.setVisibility(View.VISIBLE);
else
holder.isNewView.setVisibility(View.INVISIBLE);
int isUnread = cursor.getInt(isUnreadIndex);
if (isUnread == 1){
holder.titleView.setTextColor(textUnreadTitle);
holder.rowLayout.setBackgroundColor(bkgUnreadArticle);
} else {
holder.titleView.setTextColor(textReadTitle);
holder.rowLayout.setBackgroundColor(bkgReadArticle);
}
String url = cursor.getString(urlIndex);
String host = cursor.getString(hostIndex);
if (host.equalsIgnoreCase(Consts.HOST_LENTA) || host.equalsIgnoreCase(Consts.HOST_REALTY)) {
holder.thumbView.setVisibility(View.VISIBLE);
imageLoader.displayImage(Utils.makeImageUrl(url, Utils.THUMBNAIL), holder.thumbView);
} else
holder.thumbView.setVisibility(View.GONE);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = inflater.inflate(R.layout.articlelist_item, null);
ViewHolder holder = new ViewHolder();
holder.titleView = (TextView) v.findViewById(R.id.list_title);
holder.descriptionView = (TextView) v.findViewById(R.id.list_description);
holder.thumbView = (ImageView) v.findViewById(R.id.list_thumb);
holder.isNewView = (TextView) v.findViewById(R.id.list_read_unread);
holder.rowLayout = (LinearLayout) v.findViewById(R.id.list_row);
v.setTag(holder);
return v;
}
}
Я бы очень признателен за любую помощь в этом вопросе.
Ответы
Ответ 1
Для ListViews, GridViews и других списков, которые используются для повторного использования просмотра в своих адаптерах , вы должны вызвать .resetViewBeforeLoading()
в DisplayImageOptions, чтобы предотвратить этот эффект.
Также в документации говорится:
Init ImageLoader с настройкой только один раз
Вы делаете это только один раз? Конструктор адаптера не подходит для него.
UPD: Извините, мой ответ не полезен. .resetViewBeforeLoading()
не помогает, потому что вы используете .showStubImage(...)
. Поэтому вы должны иметь правильную работу UIL, но вы этого не делаете. И это очень странно.
Ответ 2
У меня была эта проблема на регулярной основе, хотя я только запускал ImageLoader один раз, я не делал этого только тогда, когда мне это нужно (в адаптере), после того как я изменил часть init() в классе Application он работал блестяще. Мне даже не пришлось использовать restartViewOnLoading() или setStubImage(). Здесь код при необходимости.
import android.content.Context;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
public class Application extends android.app.Application {
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
DisplayImageOptions imgOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.showImageOnLoading(R.drawable.default_picture)
.build();
ImageLoaderConfiguration imgConfig = new ImageLoaderConfiguration.Builder(mContext)
.defaultDisplayImageOptions(imgOptions)
.build();
ImageLoader.getInstance().init(imgConfig);
}
public static Context getAppContext(){
return mContext;
}
}
EDIT: вы можете проверить этот разговор здесь для более глубокого понимания проблемы.
В основном есть 3 решения
1) Установите параметры android: layout_width и android: layout_height для ImageViews в провалах ('wrap_content' и 'match_parent' неприемлемы)
2) Вызвать ImageLoader после рисования ImageView (в imageView.post(...):
imageView.post(new Runnable() {
@Override
public void run() {
imageLoader.displayImage(imageUri, imageView);
}
});
3) Передайте ImageViewAware (вместо ImageView), который не учитывает фактический размер представления:
Интерактив:
imageLoader.displayImage(imageUri, imageView);
выполните следующие действия:
ImageAware imageAware = new ImageViewAware(imageView, false)
imageLoader.displayImage(imageUri, imageAware);
Ответ 3
Просто посмотрите, как установить "Держатели" , потому что я думаю, что вы написали ошибочную логику внутри своего Adapter
, поэтому она повторяет представления.
Существует также Пользовательский адаптер курсора с держателем и обсуждение Get View и BindView.
Ответ 4
Добавьте эту строку в свой код::
holder.thumbView.setTag(Utils.makeImageUrl(url, Utils.THUMBNAIL).get(position));
imageLoader.displayImage(Utils.makeImageUrl(url, Utils.THUMBNAIL), view_holder.image);
Ответ 5
У меня такая же проблема и исправлена. Это не потому, что библиотека Universal-Image-Loader. Это связано с тем, что вы используете держатель в неправильной логике для загрузки изображения.
Попробуйте заменить
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = inflater.inflate(R.layout.articlelist_item, null);
ViewHolder holder = new ViewHolder();
holder.titleView = (TextView) v.findViewById(R.id.list_title);
holder.descriptionView = (TextView) v.findViewById(R.id.list_description);
holder.thumbView = (ImageView) v.findViewById(R.id.list_thumb);
holder.isNewView = (TextView) v.findViewById(R.id.list_read_unread);
holder.rowLayout = (LinearLayout) v.findViewById(R.id.list_row);
v.setTag(holder);
return v;
}
С
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = inflater.inflate(R.layout.articlelist_item, null);
ViewHolder holder = new ViewHolder();
holder.titleView = (TextView) v.findViewById(R.id.list_title);
holder.descriptionView = (TextView) v.findViewById(R.id.list_description);
ImageView thumbView = (ImageView) v.findViewById(R.id.list_thumb);
imageLoader.displayImage("Your image URL", thumbView);
holder.isNewView = (TextView) v.findViewById(R.id.list_read_unread);
holder.rowLayout = (LinearLayout) v.findViewById(R.id.list_row);
v.setTag(holder);
return v;
}
И не забудьте удалить imageloader в функцию bindView