android addview 闪屏,android - 在notifyDatasetChanged()之后,RecyclerView闪烁

当在RecyclerView中调用notifyDataSetChanged()后,出现了闪烁现象。问题可能源于没有使用稳定的ID,导致ViewHolder被分配到不同位置。解决方案包括:1) 使用稳定的ID并覆盖getItemId(); 2) 关闭默认的改变动画;3) 设置更改动画时长为0; 4) 使用粒度通知如notifyItemInserted()替代notifyDataSetChanged()。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值