RecyclerView blinks after notifyDatasetChanged ()

I have a RecyclerView that loads some data from an API, includes an image URL and some data, and I use networkImageView for a lazy loading image.

@Override public void onResponse(List<Item> response) { mItems.clear(); for (Item item : response) { mItems.add(item); } mAdapter.notifyDataSetChanged(); mSwipeRefreshLayout.setRefreshing(false); } 

Here is the implementation for the adapter:

 public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) { if (isHeader(position)) { return; } // - get element from your dataset at this position // - replace the contents of the view with that element MyViewHolder holder = (MyViewHolder) viewHolder; final Item item = mItems.get(position - 1); // Subtract 1 for header holder.title.setText(item.getTitle()); holder.image.setImageUrl(item.getImg_url(), VolleyClient.getInstance(mCtx).getImageLoader()); holder.image.setErrorImageResId(android.R.drawable.ic_dialog_alert); holder.origin.setText(item.getOrigin()); } 

The problem is when we update in recyclerView, it approaches a very short time at the beginning, which looks strange.

I just used the GridView / ListView, and it worked as I expected. There was no glare.

for RecycleView in onViewCreated of my Fragment :

 mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); // use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true); mGridLayoutManager = (GridLayoutManager) mRecyclerView.getLayoutManager(); mGridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return mAdapter.isHeader(position) ? mGridLayoutManager.getSpanCount() : 1; } }); mRecyclerView.setAdapter(mAdapter); 

Has anyone encountered such a problem? what could be the reason?

+100
android android-fragments android-recyclerview
Mar 29 '15 at 15:35
source share
14 answers

Try using stable identifiers in your RecyclerView.Adapter

setHasStableIds(true) and override getItemId(int position) .

Without stable identifiers, after notifyDataSetChanged() ViewHolders are usually assigned to the wrong positions. That was the reason for blinking in my case.

You can find a good explanation here.

+106
Sep 09 '15 at 19:53
source share

According to this issue page .... this is an animation of changing the default recycleview element ... you can disable it. try it

 recyclerView.getItemAnimator().setSupportsChangeAnimations(false); 

Change latest version

Quote from the Android Developers Blog :

Please note that this new API does not support backward compatibility. If you have previously implemented ItemAnimator, you can extend SimpleItemAnimator, which provides the old API by wrapping the new API. You will also notice that some methods have been completely removed from ItemAnimator. For example, if you called recyclerView.getItemAnimator (). setSupportsChangeAnimations (false), this code will no longer compile. You can replace it with:

 ItemAnimator animator = recyclerView.getItemAnimator(); if (animator instanceof SimpleItemAnimator) { ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false); } 
+94
Aug 26 '15 at 12:57
source share

It just worked:

 recyclerView.getItemAnimator().setChangeDuration(0); 
+39
Jan 19 '16 at 14:25
source share

I have the same problem loading an image from some URLs and then the imageView blinks. Solved by

 notifyItemRangeInserted() 

instead

 notifyDataSetChanged() 

allowing you to reload this unchanged old data.

+10
Sep 17 '16 at 4:37
source share

try disabling default animation

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

this is a new way to turn off animations that support Android 23

this old way will work for the old version of the support library

 recyclerView.getItemAnimator().setSupportsChangeAnimations(false) 
+9
Dec 22 '15 at 19:31
source share

Assuming mItems is a collection that supports your Adapter , why are you deleting everything and re-adding? Basically you say that everything has changed, so RecyclerView double-checks all the views, than I assume that the image library does not handle it properly, where it still resets the view, even if it is the same image URL. Perhaps they had some kind of baked solution for AdapterView, so it works fine in GridView.

Instead of calling notifyDataSetChanged , which will cause all the views to be re-linked, call up detailed event notifications (notify added / deleted / moved / updated) so that the RecyclerView jumps only the desired views and nothing flickers.

+3
Mar 30 '15 at 4:33
source share

In Kotlin, you can use the "class extension" for the RecyclerView:

 fun RecyclerView.disableItemAnimator() { (itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations = false } // sample of using in Activity: override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { myRecyclerView.disableItemAnimator() // ... } 
+3
May 23 '19 at 9:10
source share

Recyclerview uses DefaultItemAnimator as its default animator. As you can see from the code below, they change the alpha of the image owner when changing position:

 @Override public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { ... final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView); ... ViewCompat.setAlpha(oldHolder.itemView, prevAlpha); if (newHolder != null) { .... ViewCompat.setAlpha(newHolder.itemView, 0); } ... return true; } 

I wanted to keep the rest of the animation, but remove the β€œflicker” so that I clone the DefaultItemAnimator and delete the 3 alpha lines above.

To use the new animator, just call setItemAnimator () in the RecyclerView:

 mRecyclerView.setItemAnimator(new MyItemAnimator()); 
+2
Jun 29 '16 at 0:19
source share

Hey @ Maybe this could be a late replay. I also ran into this problem and solved using the solution below, this may help you check.

The LruBitmapCache.java class is created to get the image cache size.

 import android.graphics.Bitmap; import android.support.v4.util.LruCache; import com.android.volley.toolbox.ImageLoader.ImageCache; public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageCache { public static int getDefaultLruCacheSize() { final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); final int cacheSize = maxMemory / 8; return cacheSize; } public LruBitmapCache() { this(getDefaultLruCacheSize()); } public LruBitmapCache(int sizeInKiloBytes) { super(sizeInKiloBytes); } @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight() / 1024; } @Override public Bitmap getBitmap(String url) { return get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { put(url, bitmap); } } 

VolleyClient.java singleton class [extends Application] added below code

in the constructor of the Singleton class of the VolleyClient class add the fragment below to initialize ImageLoader

 private VolleyClient(Context context) { mCtx = context; mRequestQueue = getRequestQueue(); mImageLoader = new ImageLoader(mRequestQueue,getLruBitmapCache()); } 

I created a getLruBitmapCache () method to return LruBitmapCache

 public LruBitmapCache getLruBitmapCache() { if (mLruBitmapCache == null) mLruBitmapCache = new LruBitmapCache(); return this.mLruBitmapCache; } 

Hope it helps you.

+1
Jun 20 '15 at 12:10
source share

Try using stableId in the processor view. The following article briefly explains this.

https://medium.com/@hanru.yeh/recyclerviews-views-are-blinking-when-notifydatasetchanged-c7b76d5149a2

+1
Feb 28 '19 at 4:04
source share

I had a similar problem and it worked for me You can call this method to set the image cache size

 private int getCacheSize(Context context) { final DisplayMetrics displayMetrics = context.getResources(). getDisplayMetrics(); final int screenWidth = displayMetrics.widthPixels; final int screenHeight = displayMetrics.heightPixels; // 4 bytes per pixel final int screenBytes = screenWidth * screenHeight * 4; return screenBytes * 3; } 
0
Aug 13 '15 at 10:25
source share

for my application, I had some data changes, but I did not want the whole view to blink.

I solved this by only decreasing the old view by 0.5 alpha and starting newview alpha by 0.5. This created a transition of softer fading without the complete disappearance of the view.

Unfortunately, due to private implementations, I could not subclass DefaultItemAnimator to make this change, so I had to clone the code and make the following changes

in animateChange:

 ViewCompat.setAlpha(newHolder.itemView, 0); //change 0 to 0.5f 

in animateChangeImpl:

 oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { //change 0 to 0.5f 
0
Apr 25 '16 at 19:06
source share

for me recyclerView.setHasFixedSize(true); worked

0
Jun 22 '16 at 13:59 on
source share

Using appropriate recyclerview methods to update views will solve this problem.

First, make changes to the list

 mList.add(item); or mList.addAll(itemList); or mList.remove(index); 

Then report using

 notifyItemInserted(addedItemIndex); or notifyItemRemoved(removedItemIndex); or notifyItemRangeChanged(fromIndex, newUpdatedItemCount); 

Hope this helps!

0
Aug 24 '16 at 9:16
source share



All Articles