android - 在notifyDatasetChanged()之后,RecyclerView闪烁
我有一个RecyclerView,它从API加载一些数据,包括一个图像URL和一些数据,我使用networkImageView来延迟加载图像。
@Override
public void onResponse(List 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,它按预期工作。 没有瞎眼。
onViewCreated of my Fragment中的RecycleView配置:
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);
有人遇到过这样的问题吗? 可能是什么原因?
13个解决方案
97 votes
尝试在RecyclerView.Adapter中使用稳定的ID
notifyDataSetChanged()并覆盖getItemId(int position)。
没有稳定的ID,在notifyDataSetChanged()之后,ViewHolders通常被分配到不同的位置。 这就是我案件中闪烁的原因。
你可以在这里找到一个很好的解释。
Anatoly Vdovichev answered 2019-09-02T00:14:50Z
85 votes
根据这个问题页面....它是默认的recycleview项目更改动画...你可以关闭它..试试这个
recyclerView.getItemAnimator().setSupportsChangeAnimations(false);
更新最新版本
引自Android开发人员博客:
请注意,此新API不向后兼容。 如果你以前 实现了ItemAnimator,你可以改为扩展 SimpleItemAnimator,它通过包装新的API来提供旧的API API。 您还会注意到某些方法已被完全删除 来自ItemAnimator。 例如,如果你打电话 recyclerView.getItemAnimator()。setSupportsChangeAnimations(假), 此代码将不再编译。 您可以将其替换为:
ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
Sabeer Mohammed answered 2019-09-02T00:15:39Z
34 votes
这简单有效:
recyclerView.getItemAnimator().setChangeDuration(0);
Hamzeh Soboh answered 2019-09-02T00:16:03Z
8 votes
我有一些问题从一些网址加载图像,然后imageView闪烁。通过使用解决
notifyItemRangeInserted()
代替
notifyDataSetChanged()
这避免了重新加载那些未更改的旧数据。
Wesely answered 2019-09-02T00:16:40Z
7 votes
尝试此操作以禁用默认动画
ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
这是自Android支持23以来禁用动画的新方法
这种旧方法适用于旧版本的支持库
recyclerView.getItemAnimator().setSupportsChangeAnimations(false)
Mohamed Farouk answered 2019-09-02T00:17:17Z
2 votes
假设notifyDataSetChanged是支持Adapter的集合,为什么要删除所有内容并重新添加? 你基本上告诉它一切都已经改变,所以RecyclerView重新绑定所有视图,而不是我假设图像库没有正确处理它仍然重置视图,即使它是相同的图像URL。 也许他们在AdapterView的解决方案中有一些很好用,所以它在GridView中运行良好。
调用粒度通知事件(通知已添加/删除/移动/更新),而不是调用将导致重新绑定所有视图的notifyDataSetChanged,以便RecyclerView将仅重新绑定必要的视图,并且不会闪烁任何内容。
yigit answered 2019-09-02T00:17:49Z
2 votes
Recyclerview使用DefaultItemAnimator作为默认动画师。从下面的代码中可以看出,它们会在项目更改时更改视图持有者的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;
}
我想保留其余的动画,但删除“闪烁”,所以我克隆了DefaultItemAnimator并删除了上面的3个alpha行。
要使用新的动画师,只需在您的RecyclerView上调用setItemAnimator():
mRecyclerView.setItemAnimator(new MyItemAnimator());
Peter File answered 2019-09-02T00:18:26Z
1 votes
嘿@Ali可能是迟到的回复。 我也遇到了这个问题并通过以下解决方案解决,它可以帮助您检查。
创建LruBitmapCache.java类以获取图像缓存大小
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import com.android.volley.toolbox.ImageLoader.ImageCache;
public class LruBitmapCache extends LruCache 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单例类[extends Application]在代码下面添加了
在VolleyClient单例类构造函数中添加下面的代码片段来初始化ImageLoader
private VolleyClient(Context context)
{
mCtx = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,getLruBitmapCache());
}
我创建了getLruBitmapCache()方法来返回LruBitmapCache
public LruBitmapCache getLruBitmapCache() {
if (mLruBitmapCache == null)
mLruBitmapCache = new LruBitmapCache();
return this.mLruBitmapCache;
}
希望它会帮助你。
Android learner answered 2019-09-02T00:19:22Z
0 votes
我有类似的问题,这对我有用您可以调用此方法来设置图像缓存的大小
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;
}
developer_android answered 2019-09-02T00:19:47Z
0 votes
对于我的应用程序,我有一些数据更改但我不希望整个视图闪烁。
我解决了它只是将旧视图淡化0.5 alpha并开始新视图alpha为0.5。 这样可以创建更柔和的渐变过渡,而不会使视图完全消失。
不幸的是,由于私有实现,我无法继承DefaultItemAnimator以进行此更改,因此我不得不克隆代码并进行以下更改
在animateChange中:
ViewCompat.setAlpha(newHolder.itemView, 0); //change 0 to 0.5f
在animateChangeImpl中:
oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { //change 0 to 0.5f
Deefer answered 2019-09-02T00:20:37Z
0 votes
对我来说recyclerView.setHasFixedSize(true);工作
Pramod answered 2019-09-02T00:21:01Z
0 votes
使用适当的recyclerview方法更新视图将解决此问题
首先,在列表中进行更改
mList.add(item);
or mList.addAll(itemList);
or mList.remove(index);
然后通知使用
notifyItemInserted(addedItemIndex);
or
notifyItemRemoved(removedItemIndex);
or
notifyItemRangeChanged(fromIndex, newUpdatedItemCount);
希望这会有所帮助!!
Sreedhu Madhu answered 2019-09-02T00:21:44Z
0 votes
尝试在recycler视图中使用stableId。 以下文章简要解释了它
[https://medium.com/@hanru.yeh/recyclerviews-views-are-blinking-when-notifydatasetchanged-c7b76d5149a2]
Farruh Habibullaev answered 2019-09-02T00:22:16Z