Recyclerview Adapter и Glide - едно и също изображение на всеки 4-5 реда

Имам този проблем - само за тестови цели добавих ParseFile към един от ParseObject от получения списък. Вместо да го показва само в този ред, той се показва на всеки 4-5 реда, понякога повече, понякога по-малко. Подозирам, че изгледът за рециклиране има нещо общо с това. Странно, други данни (изтрити от този пример) работят добре с променлива position.

@Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        if(parseList.get(position).get("logo") != null){
            ParseFile image = (ParseFile) parseList.get(position).get("logo");
            String url = image.getUrl();
            Glide.with(context)
                    .load(url)
                    .placeholder(R.drawable.piwo_48)
                    .transform(new CircleTransform(context))
                    .into(holder.imageView);


        }

    }

person jean d'arme    schedule 21.09.2015    source източник


Отговори (5)


Отговорите тук са неверни, въпреки че са на прав път.

Трябва да извикате Glide#clear(), а не просто да зададете изображението, което може да бъде изтеглено, на нула. Ако не извикате clear(), асинхронно зареждане, завършващо неправилно, все още може да причини проблеми с рециклирането на изгледа. Вашият код трябва да изглежда така:

@Override 
public void onBindViewHolder(ViewHolder holder, int position) {
    if (parseList.get(position).get("logo") != null) {
        ParseFile image = (ParseFile) parseList.get(position).get("logo");
        String url = image.getUrl();
        Glide.with(context) 
                .load(url)
                .placeholder(R.drawable.piwo_48)
                .transform(new CircleTransform(context)) 
                .into(holder.imageView);
    } else {
        // make sure Glide doesn't load anything into this view until told otherwise
        Glide.with(context).clear(holder.imageView);
        // remove the placeholder (optional); read comments below
        holder.imageView.setImageDrawable(null);
    }
} 
person Sam Judd    schedule 24.09.2015
comment
Бихте ли разяснили повече за това? Предишните отговори работят добре, но си представям, че методът „clear()“ не е внедрен просто от нищото. - person jean d'arme; 24.09.2015
comment
Те просто работят предимно. Ако извикате onBindViewHolder и започнете зареждане за позиция с лого за даден изглед, след което извикате отново onBindViewHolder със същия ViewHolder, преди зареждането да приключи, ще видите старото изображение вместо празен изглед. Това състояние на състезание е много по-рядко срещано от предишната ви грешка, но все пак е възможно. - person Sam Judd; 24.09.2015
comment
Също така трябва да изясня, че написах библиотеката и метода clear(). Този случай на използване тук е чудесен пример защо методът clear() съществува :). Винаги трябва или да започнете ново зареждане (което анулира старото зареждане вместо вас), или да отмените зареждането сами, когато използвате повторно изгледи. - person Sam Judd; 24.09.2015
comment
Чакай малко - ти си написал Glide, този от Bumptech? :)) - person jean d'arme; 24.09.2015
comment
Добре, най-накрая получих шанс да накарам това да работи и... това решение не работи за мен :( Показва контейнер в тези елементи, където не трябва да показва нищо. - person jean d'arme; 24.09.2015
comment
Ако не искате контейнерът да се показва, можете да извикате setImageDrawable(null) след извикването clear(). clear() просто гарантира, че Glide няма да прави нищо с изгледа в бъдеще (ако асинхронното зареждане завърши по-късно). - person Sam Judd; 25.09.2015
comment
След много болка открих, че това е единственият отговор, който работи! Благодаря! - person Jonathan Dunn; 19.04.2018
comment
Вероятно трябва да използвате Glide.with(context).clear(view) - person w201; 15.02.2019
comment
@SamJudd Това всъщност е интересно поведение на Glide. В iOS не можах просто да асинхронно заредя изображение в изглед на изображение в клетка, която е била рециклирана. Ще има условия за състезание и показани грешни изображения. И Glide автоматично отменя предишния процес на зареждане в същия изглед? - person Manuel; 07.05.2019
comment
@SamJudd, казахте Винаги или трябва да започнете ново зареждане (което анулира старото зареждане вместо вас), или да отмените зареждането сами, когато използвате повторно изгледи. Какво ще стане, ако превъртите малко по-бързо в изглед за рециклиране и много скоро попаднете на изглед(и), които трябва да заредят същия URL? Те ще продължат да отменят предишни и да правят нови заявки. Знам, че това е доста рядък случай, но има ли начин да се провери кои са текущите в момента, вътре в onBindViewHolder? - person Rosen Dimov; 31.10.2020

Може би трябва да опитате нещо подобно

.signature(new StringSignature(String.valueOf(System.currentTimeMillis())))

проба:

Glide.with(context)
                .load(url)
                .placeholder(R.drawable.progress_animation)
                .crossFade()
                .signature(new StringSignature(String.valueOf(System.currentTimeMillis())))
                .error(R.drawable.image_error_404)
                .into(iv);
person Aleksey Timoshchenko    schedule 15.02.2017

В RecyclerView всеки ред се рециклира с нови данни. Във вашия код вие задавате ImageView само когато не е null и в противен случай не правите нищо. В този случай, когато не е нула, ImageView ще покаже старо изображение, тъй като не сте направили override за текущия обект. Можете да поправите това, като добавите условие else и зададете ImageView на null/blank нещо.

@Override 
    public void onBindViewHolder(ViewHolder holder, int position) {
        if(parseList.get(position).get("logo") != null){
            ParseFile image = (ParseFile) parseList.get(position).get("logo");
            String url = image.getUrl();
            Glide.with(context) 
                    .load(url)
                    .placeholder(R.drawable.piwo_48)
                    .transform(new CircleTransform(context)) 
                    .into(holder.imageView);


        } 
        else{
            holder.imageView.setImageDrawable(null);
        }
    } 
person Sharj    schedule 21.09.2015
comment
Знаех, че е нещо с рециклиране на изглед, но никога не съм мислил по този начин. Благодаря много за това, работи веднага :) - person jean d'arme; 22.09.2015
comment
Този отговор е непълен. Трябва също така да извикате Glide.clear() във въпросния изглед на изображение, в противен случай все още може да видите проблеми с повторното използване на клетката, когато асинхронното зареждане завърши по-късно. - person Sam Judd; 24.09.2015
comment
@samajudd Току-що намерих този - така че трябва да се обадя и на setImageDrawable(null), и на Glide.clear()? - person jean d'arme; 24.09.2015
comment
Странно нещо - когато имам внедрени и двата отговора и clear() е първи, получавам само едно излишно изображение, но когато clear() се извика второ, работи. Така ли бихте направили това @samajudd? - person jean d'arme; 24.09.2015

Когато „лого“ е нула, получавате рециклираното изображение, вместо да го изчистите. Добавете този код, за да изчистите правилно изображението:

holder.imageView.setImageDrawable(null);
person BladeCoder    schedule 21.09.2015

Мисля, че е така, защото вашият адаптер има adapter.setHasStableIds(true) е true и getItemId не е заменен. Така че recyclerView опитайте да намерите притежател със същия идентификатор и го използвайте повторно.

person Pavlo Zoria    schedule 19.07.2018