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 Fragment
configuration:
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);
希望这会有所帮助!