notifyDatasetChanged()后,RecyclerView闪烁

我有一个RecyclerView从API加载一些数据,包括一个图像的URL和一些数据,我使用networkImageView来延迟加载图像。

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

这是适配器的实现:

 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()); } 

问题是当我们在recyclerView刷新的时候,一开始看起来很奇怪。

我只是使用了GridView / ListView,而且按照我的预期工作。 没有blincking。

onViewCreated of my Fragment onViewCreated onViewCreated of my Fragmentconfiguration:

 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); 

任何人都面临这样的问题? 可能是什么原因?

尝试在您的RecyclerView.Adapter中使用稳定的ID

setHasStableIds(true)并重写getItemId(int position)

如果没有稳定的ID,在notifyDataSetChanged() ,ViewHolders通常被分配到不同的位置。 这就是我眨眼的原因。

根据这个问题页面….这是默认的recycleview项目更改animation…你可以把它closures..试试这个

 recyclerView.getItemAnimator().setSupportsChangeAnimations(false); 

更改最新版本

从Android开发者博客引用:

请注意,这个新的API不是向后兼容的。 如果以前实现了ItemAnimator,则可以扩展SimpleItemAnimator,它通过包装新API来提供旧API。 您还会注意到一些方法已经完全从ItemAnimator中删除。 例如,如果您正在调用recyclerView.getItemAnimator()。setSupportsChangeAnimations(false),则此代码将不再编译。 您可以将其replace为:

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

这只是工作:

 recyclerView.getItemAnimator().setChangeDuration(0); 

试试这个来禁用默认的animation

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

这是自从android支持23以来禁用animation的新方法

这种旧的方式将适用于旧版本的支持库

 recyclerView.getItemAnimator().setSupportsChangeAnimations(false) 

我有相同的问题加载图像从一些url和imageView闪烁。 通过使用解决

 notifyItemRangeInserted() 

代替

 notifyDataSetChanged() 

避免重新加载那些不变的旧数据。

假设mItems是支持您的Adapter的集合,为什么要删除所有内容并重新添加? 你基本上是在告诉它一切都改变了,所以RecyclerView重新绑定所有的视图,而不是我认为图像库不能正确处理它仍然重置视图,即使它是相同的图像url。 也许他们有一些在AdapterView的解决scheme,以便它在GridView中正常工作。

而不是调用notifyDataSetChanged ,这将导致重新绑定所有视图,调用粒度通知事件(通知添加/删除/移动/更新),以便RecyclerView将只重新绑定必要的视图,什么也不会闪烁。

嘿@Ali可能会迟到重播。 我也面临这个问题,并用下面的解决scheme解决,它可以帮助您检查。

创buildLruBitmapCache.java类来获取图像caching大小

 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单例类[扩展应用程序]下面添加代码

在VolleyClient单例类的构造函数中添加下面的代码片段来初始化ImageLoader

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

我创build了getLruBitmapCache()方法来返回LruBitmapCache

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

希望它会帮助你。

Recyclerview使用DefaultItemAnimator作为默认的animation器。 正如你可以从下面的代码中看到的,他们改变了视图持有者在更改项目时的alpha值:

 @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; } 

我想保留其余的animation,但删除了“闪烁”,所以我克隆了DefaultItemAnimator并删除了上面的3个alpha线。

要使用新的animation师,只需在您的RecyclerView上调用setItemAnimator():

 mRecyclerView.setItemAnimator(new MyItemAnimator()); 

我有类似的问题,这对我有用您可以调用此方法来设置图像caching的大小

 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.5 alpha,然后在0.5开始新视图alpha。 这创造了一个更柔和的衰落过渡而不会使视图完全消失。

不幸的是,由于私有实现,我无法inheritanceDefaultItemAnimator以进行此更改,因此我必须克隆代码并进行以下更改

在animateChange中:

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

在animateChangeImpl中:

 oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { //change 0 to 0.5f 

对我来说recyclerView.setHasFixedSize(true); 工作

使用适当的recyclerview方法来更新视图将解决这个问题

首先,在列表中进行更改

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

然后通知使用

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

希望这会有所帮助!