Yoyoy Chu
Yoyoy Chu

Reputation: 639

Why Glide blink the item ImageView when notifydatasetchanged

I am using Glide 3.7.0 with RecyclerView. The item view always blinks when refreshing (calling notifyDataSetChanged).

Here is my code:

Glide
  .with(context)
  .load(filepath)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .skipMemoryCache(true)
  .dontAnimate()
  .into(imageview);

When I use no cache, the ImageView has a null Bitmap when notifyDataSetChanged method is called and Glide hasn't finished loading the bitmap.

If I use the code below:

Glide
  .with(context)
  .load(filepath)
  .dontAnimate()
  .into(imageview);

Then the item ImageView does not blink anymore (using cache).

I want to update the item view dynamically, so I disable the glide cache.

Are there any solutions to solve this blink bug?

Thank you very much!

Upvotes: 20

Views: 16925

Answers (10)

FarVoyager
FarVoyager

Reputation: 59

For me the solution was to add .placeholder() to Glide builder:

            Glide.with(view)
            .load(picture)
            .placeholder(placeholderImg)
            .into(view)

Upvotes: 0

Volodymyr Kim
Volodymyr Kim

Reputation: 1

yourRecyclerView.itemAnimator = null

Upvotes: 0

szaske
szaske

Reputation: 2027

None of the previous answers solved my problem, which was all the items in the viewholder blinking on update. In my case I was using

notifyItemChanged(Index)

If you think about it, it makes sense that the item would blink since I was specifically telling the viewholder to update that item in the list. In my case only one of eight things was actually getting updated in the viewholder, but my code only had one way to onBindViewHolder. Well it turns out the RecyclerView.Adapter class has a second onBindViewHolder function that allows you to only update part of your viewholder if that's all you need. The signature is

onBindViewHolder(holder: CommentViewHolder, position: Int, payloads: MutableList<Any>)

And you can read about it here. This worked for me.

Upvotes: 0

CarlosOliveira
CarlosOliveira

Reputation: 31

For those who are working with kotlin and BindAdapter, this worked for me:

@BindingAdapter("imageUrl", "error", "placeholder")
fun ImageView.loadImage(imageUrl: String?, error: Drawable, placeholder: Drawable) {

    if (imageUrl.isNullOrBlank()) {
        setImageDrawable(error)
    } else {

        try {
            Glide
            .with(context)
            .asBitmap()
            .load(imageUrl)
            .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
            .skipMemoryCache(true)
            .dontAnimate()
            .into(object: CustomTarget<Bitmap?>() {
                override fun onResourceReady(
                    resource: Bitmap,
                    transition: Transition<in Bitmap?>?,
                ) {
                    setImageBitmap(resource)
                }

                override fun onLoadCleared(placeholder: Drawable?) {
                    setImageDrawable(placeholder)
                }

            })
        } catch (e: Exception) {
            setImageDrawable(placeholder)
        }
    }
}

Upvotes: 3

Ashwin Khadgi
Ashwin Khadgi

Reputation: 322

try the below Glide.with(this).load(photoToLoad.getPath()).placeholder(imageView.getDrawable()).into(imageView);

Upvotes: 2

Daniil Andashev
Daniil Andashev

Reputation: 174

Also don't forget to setHasStableIds(true); in your adapter and properly override getItemId() method.
See: example how to do it

Upvotes: 2

Filipkowicz
Filipkowicz

Reputation: 669

since SimpleTarget is deprecated try this solution:

GlideApp.with(SOMETHING)
                                .load("WHAT")
                                .dontAnimate()
                                .let { request ->
                                    if(imageView.drawable != null) {
                                        request.placeholder(imageView.drawable.constantState?.newDrawable()?.mutate())
                                    } else {
                                        request
                                    }
                                }
                                .into(imageView)

you can also create nice extension for drawable to make REAL copy:

import android.graphics.drawable.Drawable

fun Drawable.copy() = constantState?.newDrawable()?.mutate()

Upvotes: 5

MakBeard
MakBeard

Reputation: 280

Update Glide from version 3 to 4 and setSupportsChangeAnimations(false) for RecyclerView solved problem for me

RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
    ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}

Upvotes: 5

john invictus
john invictus

Reputation: 69

In my case, I solved the issue by using defined dimensions on my imageView.

<ImageView
        android:id="@+id/poster_imageview"
        android:layout_width="130dp"
        android:layout_height="183dp"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"
        android:src="@drawable/placeholder" />

Upvotes: 2

Yoyoy Chu
Yoyoy Chu

Reputation: 639

After my many tries, just use SimpleTarget solved my problem thank you!

Glide
.with(context)
.load(filepath)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.dontAnimate()
.into(new SimpleTarget<Bitmap>() {

            @Override
            public void onResourceReady(Bitmap arg0, GlideAnimation<? super Bitmap> arg1) {
                // TODO Auto-generated method stub
                holder.mItemView.setImageBitmap(arg0);
            }
        });

Upvotes: 32

Related Questions