RecyclerView的item改变UI闪动问题

本文深入探讨了Android RecyclerView在使用notifyItemChanged方法时出现闪烁的原因,分析了源码中第三个参数的作用,以及如何通过正确传递参数避免全屏刷新,从而解决闪烁问题。

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

闪动原因:是调用notifyItemChanged方法时传了一个参数,查看源码

//刷新单个item的方法,调用notifyItemRangeChanged
public final void notifyItemChanged(int position) {
   this.mObservable.notifyItemRangeChanged(position, 1);
}
//第三个参数为null
//@param payload Optional parameter, use null to identify a "full" update
//如果传入null则全部刷新
public void notifyItemRangeChanged(int positionStart, int itemCount) {
    this.notifyItemRangeChanged(positionStart, itemCount, (Object)null);
}

第三个参数为null会导致全部刷新,所以会item会闪动
解决方法:

adapter.notifyItemChanged(position, position);or在adapter里冲下方法notifyItemChanged();

解决原因:

//调用刷新时第二个参数会当做第三个参数传到调用方法里
public final void notifyItemChanged(int position, @Nullable Object payload) {
   this.mObservable.notifyItemRangeChanged(position, 1, payload);
}
//这样就值刷新局部了,并不会刷新了
public void notifyItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
            for(int i = this.mObservers.size() - 1; i >= 0; --i) {
                ((RecyclerView.AdapterDataObserver)this.mObservers.get(i)).onItemRangeChanged(positionStart, itemCount, payload);
            }

        }

 

package com.lc.bailingbird; import static com.lc.bailingbird.base.BaseApplication.Blistener; import static com.lc.bailingbird.base.BaseApplication.bluetoothSDK; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentResultListener; import androidx.viewpager2.adapter.FragmentStateAdapter; import androidx.viewpager2.widget.ViewPager2; import com.bes_ota.bluetoothsdk.BluetoothSDK; import com.google.android.material.badge.BadgeDrawable; import com.lc.bailingbird.base.BaseActivity; import com.lc.bailingbird.base.BaseApplication; import com.lc.bailingbird.conn.BaseAsyCallBack; import com.lc.bailingbird.conn.CartListPost; import com.lc.bailingbird.databinding.ActivityMainBinding; import com.lc.bailingbird.dialog.CommonDialog; import com.lc.bailingbird.fragment.ChatFragment; import com.lc.bailingbird.fragment.HomeFragmentNew; import com.lc.bailingbird.fragment.MarketFragment; import com.lc.bailingbird.fragment.MineFragment; import com.lc.bailingbird.fragment.MyFragment; import com.lc.bailingbird.fragment.NewsFragment; import com.lc.bailingbird.home.GoodDetailActivity; import com.lc.bailingbird.home.NewcomerGuideActivity; import com.lc.bailingbird.home.WebActivity; import com.lc.bailingbird.home.launcherActivity; import com.lc.bailingbird.login.ForgetPWDActivity; import com.lc.bailingbird.login.LoginActivity; import com.lc.bailingbird.login.RegisterActivity; import com.lc.bailingbird.mine.WelcomeActivity; import com.lc.bailingbird.util.BluetoothUtil; import com.lc.bailingbird.util.GlideImageLoader; import com.lc.bailingbird.util.SPManager; import com.mob.MobSDK; import com.petterp.floatingx.FloatingX; import com.petterp.floatingx.assist.FxGravity; import com.petterp.floatingx.assist.helper.AppHelper; import com.petterp.floatingx.impl.lifecycle.FxTagActivityLifecycleImpl; import com.qiyukf.nimlib.sdk.StatusBarNotificationConfig; import com.qiyukf.unicorn.api.ConsultSource; import com.qiyukf.unicorn.api.OnMessageItemClickListener; import com.qiyukf.unicorn.api.Unicorn; import com.qiyukf.unicorn.api.YSFOptions; import com.qiyukf.unicorn.ui.activity.LeaveMessageActivity; import com.qiyukf.unicorn.ui.activity.ServiceMessageActivity; import com.tencent.bugly.crashreport.CrashReport; import com.zcx.helper.view.toast.ToastUtils; public class MainActivity extends BaseActivity<ActivityMainBinding> { FragmentStateAdapter adapter; // boolean ISCLICK = true; // CommonDialog dialog; @Override protected void iniClick() { getSupportFragmentManager().setFragmentResultListener("position", this, new FragmentResultListener() { @Override public void onFragmentResult(@NonNull String requestKey, @NonNull Bundle result) { Log.e("HOME_TAG", "滑动?" + result.getInt("position")); binding.viewpager.setCurrentItem(result.getInt("position"), true); if (result.getInt("position") == 1 && result.containsKey("title")) { getSupportFragmentManager().setFragmentResult("classTitle", result); } } }); } @Override public void iniView() { super.iniView(); // dialog = new CommonDialog(MainActivity.this, "提示", "客服功能需要麦克风权限"); binding.viewpager.setAdapter(adapter = new FragmentStateAdapter(this) { @NonNull @Override public Fragment createFragment(int position) { switch (position) { case 0: return new NewsFragment(); case 1: return new MarketFragment(); case 2: return new HomeFragmentNew(); case 3: return new ChatFragment(); default: return new MineFragment(); } } @Override public int getItemCount() { return 5; } }); binding.viewpager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { super.onPageSelected(position); switch (position) { case 0: binding.tab.setSelectedItemId(R.id.menu_news); break; case 1: binding.tab.setSelectedItemId(R.id.menu_market); break; case 2: binding.tab.setSelectedItemId(R.id.menu_home); break; case 3: binding.tab.setSelectedItemId(R.id.menu_message); break; case 4: binding.tab.setSelectedItemId(R.id.menu_my); break; } } }); // binding.tab.setSelectedItemId(R.id.menu_home); binding.tab.setOnItemSelectedListener(item -> { int itemId = item.getItemId(); if (itemId == R.id.menu_news) { binding.viewpager.setCurrentItem(0, true); return true; } else if (itemId == R.id.menu_market) { binding.viewpager.setCurrentItem(1, true); return true; } else if (itemId == R.id.menu_home) { binding.viewpager.setCurrentItem(2, true); return true; } else if (itemId == R.id.menu_message) { if (!SPManager.get().getLoginStatus()) { LoginActivity.start(this); return false; } binding.viewpager.setCurrentItem(3, true); return true; } else if (itemId == R.id.menu_my) { if (!SPManager.get().getLoginStatus()) { LoginActivity.start(this); return false; } binding.viewpager.setCurrentItem(4, true); return true; } return false; }); } @Override protected void onDestroy() { super.onDestroy(); // EventBus.getDefault().unregister(this); } public void setPrivate() { MobSDK.submitPolicyGrantResult(true); CrashReport.initCrashReport(getApplicationContext(), "2a231036be", false); } @Override protected void onResume() { super.onResume(); getCartNum(); } public void getCartNum() { new CartListPost(new BaseAsyCallBack<CartListPost.RespBean>(MainActivity.this) { @Override protected void onStart() { super.onStart(); } @Override protected void onSuccess(String toast, CartListPost.RespBean bean) { BadgeDrawable badge = binding.tab.getOrCreateBadge(R.id.menu_message); if (bean.getResult().isEmpty()) { binding.tab.removeBadge(R.id.menu_message); } else { if (bean.getResult().size() > 0) { badge.setVisible(true); badge.setVerticalOffset(10); badge.setNumber(bean.getResult().get(0).getList().size()); badge.setBackgroundColor(Color.parseColor("#F30B14")); badge.setBadgeTextColor(Color.parseColor("#FFFFFF")); badge.setMaxCharacterCount(99); } else { binding.tab.removeBadge(R.id.menu_message); } } } @Override protected void onFail(String toast) { ToastUtils.show(toast); } @Override protected void onEnd(String toast) { super.onEnd(toast); } }).execute(false); } private long mExitTime; @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if ((System.currentTimeMillis() - mExitTime) > 2000) { ToastUtils.show("再按一次退出APP"); mExitTime = System.currentTimeMillis(); } else { //后台运行 不结束程序 只是退出到后台 Intent intent = new Intent(); intent.setAction("android.intent.action.MAIN"); intent.addCategory("android.intent.category.HOME"); startActivity(intent); //System.exit(0); //常规java、c#的标准退出法,返回值为0代表正常退出 结束程序 } return true; } return super.onKeyDown(keyCode, event); } } 怎么在ViewPager滑动的时候添加是否登录验证
07-10
RecyclerView滚动过程中Item闪烁是一个常见的问题,通常与ViewHolder的复用机制、图像加载过程中的异步处理以及动画效果相关。以下是几种有效的解决方案: - **避免重复加载图像**:在绑定数据时,如果图像正在加载,而ViewHolder已经被复用到其他Item上,可能会导致图像错位或闪烁。可以通过取消之前未完成的任务来解决这一问题。例如,在`onBindViewHolder`中设置新的图像请求前,先取消旧的异步任务[^5]。 ```java public class MyViewHolder extends RecyclerView.ViewHolder { private ImageView imageView; private BitmapWorkerTask currentTask; public void bind(int position) { if (currentTask != null) { currentTask.cancel(true); } currentTask = new BitmapWorkerTask(imageView); currentTask.execute(position); } } ``` - **使用图片加载库的防闪烁功能**:许多流行的图像加载库(如Glide或Picasso)提供了防止闪烁的功能选项,可以在加载新图像时保持之前的图像不变,直到新图像完全加载完成。 ```java Glide.with(context) .load(imageUrl) .placeholder(R.drawable.placeholder) // 占位符可选 .into(imageView); ``` - **禁用默认动画**:RecyclerView默认带有`DefaultItemAnimator`,这可能导致在刷新列表时出现不必要的动画效果,从而引起闪烁。可以尝试移除或自定义动画以消除闪烁现象。 ```java recyclerView.setItemAnimator(null); // 或者使用自定义的ItemAnimator ``` - **设置固定大小**:当RecyclerView的内容尺寸不会随着数据更新而改变时,可以通过调用`setHasFixedSize(true)`来优化性能,这样RecyclerView就不会每次数据变化时都重新计算其尺寸,有助于减少闪烁[^4]。 ```java recyclerView.setHasFixedSize(true); ``` - **确保正确的数据绑定逻辑**:在`onBindViewHolder`方法中,要确保为每个位置提供一致的数据UI状态。如果有条件判断影响了UI元素的状态,需要覆盖所有可能的情况,以免因复用导致显示错误的内容。 通过上述方法之一或组合应用,应该能够显著减轻甚至解决RecyclerView滚动时Item闪烁的问题。根据具体情况选择最合适的策略进行实施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值