facebook / fresco

An Android library for managing images and the memory they use.
https://frescolib.org/
MIT License
17.07k stars 3.75k forks source link

GIF images blink when `notifyItemChanged` is called #2636

Open konaire opened 3 years ago

konaire commented 3 years ago

Description

GIF images blink when notifyItemChanged is called, even non-animated GIFs (1 frame). Non-animated image formats (jpg, png) do not blink. It seems that it happens because I set a controller to SimpleDraweeView in onBindViewHolder (see the example below). But from what I understand it's the recommended way to load images. Is there any setting that I could use to disable blinking of GIF images?

Reproduction

Kotlin code ```kotlin class MainActivity : AppCompatActivity() { private var adapter: SimpleAdapter? = null override fun onCreate(savedInstanceState: Bundle?) { Fresco.initialize(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) adapter = SimpleAdapter() val recyclerView = findViewById(R.id.recyclerView) recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.itemAnimator = null recyclerView.adapter = adapter cycle() } // this function calls `notifyItemChanged` on all items every 0.5s to show that gifs blink but other images don't private fun cycle() { Handler(Looper.getMainLooper()).postDelayed({ adapter?.notifyItemChanged(0) adapter?.notifyItemChanged(1) adapter?.notifyItemChanged(2) cycle() }, 500) } } private class SimpleAdapter : RecyclerView.Adapter() { val uris = listOf( Uri.parse("https://upload.wikimedia.org/wikipedia/ru/archive/6/6b/20210505175821%21NyanCat.gif"), Uri.parse("https://s3.amazonaws.com/TWFiles/120509/userAvatar/tf_1a50094b-85ec-41b9-8469-287755c1644f.Untitled-1.gif"), Uri.parse("https://avatars.githubusercontent.com/u/6083728?s=60&v=4") ) override fun getItemCount(): Int = uris.size override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder { val inflater = LayoutInflater.from(parent.context) val itemView = inflater.inflate(R.layout.drawee_recycler_item, parent, false) return SimpleViewHolder(itemView) } override fun onBindViewHolder(holder: SimpleViewHolder, position: Int) { holder.bind(uris[position]) } } private class SimpleViewHolder(view: View) : RecyclerView.ViewHolder(view) { private val image = itemView.findViewById(R.id.image) fun bind(uri: Uri) { val controller = Fresco.newDraweeControllerBuilder() .setUri(uri) .setAutoPlayAnimations(true) .build() image.controller = controller } } ```

Layouts:

activity_main.xml ```xml ```
drawee_recycler_item.xml ```xml ```

Additional Information

stale[bot] commented 2 years ago

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "bug" or "enhancement" and I will leave it open. Thank you for your contributions.

konaire commented 2 years ago

The issue happens still and I think I don't have permissions to change the labels.

oprisnik commented 2 years ago

Hi! Yes, if you re-load an image by setting a new URL (which seems to happen when your notifyDatasetChanged is called), the image will blink. Can you only reload if there is an actual change in your dataset? The reason why normal images do not blink is that they are still in the cache and there is no animation to reset, so we can immediately fetch again from cache and display. In any case, this is not very performant.

konaire commented 2 years ago

Can you only reload if there is an actual change in your dataset?

Yes, that's what we do usually. The original code in this issue is only an extreme example. We use DiffUtils to determine which item has to be changed and then update only the said item. The issue is that the image doesn't blink if we update a TextView in an item with a static image (jpg, png) so the user doesn't feel that the image changes. But it's not the case for items with gifs since a gif blinks when the item is updated even if the image stays the same.