自定义RecyclerView滚动卡顿求助:已用ViewHolder仍卡顿
解决RecyclerView滚动卡顿与代码编译错误问题
嘿,我先帮你搞定最显眼的编译错误,再一步步解决滚动卡顿的核心问题:
一、先修复编译错误:RecyclerView被当成ListView使用了
你在ListViewActivity里犯了个小错误:XML布局里明明是RecyclerView,但你却用ListView类型去引用它,而且CustomAdapter是给RecyclerView用的,和ListView的Adapter完全不兼容,这就是报错的原因。
修复后的代码如下:
// 把ListView改成RecyclerView类型 RecyclerView recyclerView = findViewById(R.id.listView); // 注意!RecyclerView必须设置LayoutManager才能显示内容,这很容易忘 recyclerView.setLayoutManager(new LinearLayoutManager(this)); CustomAdapter customAdapter = new CustomAdapter(ListViewActivity.this, immagineDei, nomeDei); recyclerView.setAdapter(customAdapter);
二、解决RecyclerView滚动卡顿问题
你现在用setImageResource()加载drawable时,系统会在主线程完成图片解码操作——60张图片的话,滚动时主线程被阻塞,自然就卡顿了。下面是几种优化方案,按推荐程度排序:
1. 使用成熟的图片加载库(强推)
Glide、Picasso这类库会自动帮你处理后台解码、内存缓存、磁盘缓存、图片缩放等优化,完全不用自己写复杂的线程逻辑,省心又高效。
以Glide为例:
首先在模块级的build.gradle里添加依赖:
dependencies { implementation 'com.github.bumptech.glide:glide:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' }
然后修改CustomViewHolder的bind方法:
void bind(int imageId, String name) { Glide.with(itemView.getContext()) .load(imageId) .into(mFlag); // 自动处理后台解码和缓存 mName.setText(name); }
你还可以加个占位图或者错误图,提升用户体验:
Glide.with(itemView.getContext()) .load(imageId) .placeholder(R.drawable.placeholder_image) // 加载中的占位图 .error(R.drawable.error_image) // 加载失败时显示的图 .into(mFlag);
2. 手动在后台线程解码图片(不推荐,适合不想用第三方库的场景)
如果你不想引入第三方库,可以用Coroutine或者AsyncTask在后台解码图片,再回到主线程设置。但这种方式需要自己处理缓存,否则每次滚动都会重复解码,反而可能更糟:
用Coroutine的示例(需要Java Coroutine支持):
void bind(int imageId, String name) { mName.setText(name); // 后台线程解码图片 CoroutineScope(Dispatchers.IO).launch(() -> { Drawable drawable = ResourcesCompat.getDrawable(itemView.getResources(), imageId, null); // 缩放图片到ImageView的实际尺寸,避免加载过大的Bitmap占用内存 Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, mFlag.getWidth(), mFlag.getHeight(), true); // 回到主线程设置图片 CoroutineScope(Dispatchers.Main).launch(() -> { mFlag.setImageBitmap(scaledBitmap); }); }); }
3. 其他辅助优化点
- 给ImageView固定宽高:在
listview_item.xml里给ImageView设置明确的android:layout_width和android:layout_height,避免RecyclerView反复计算布局尺寸,拖慢滚动速度。 - 开启RecyclerView的稳定ID:在
CustomAdapter里添加setHasStableIds(true),并重写getItemId方法,帮助RecyclerView更高效地复用ViewHolder:public CustomAdapter(Context context, int[] immagineDio, String[] nomeDio){ // ... 原有代码 setHasStableIds(true); } @Override public long getItemId(int position) { return immagineDio[position]; // 用图片ID作为稳定标识,比position更可靠 } - 减少过度绘制:在开发者选项里开启「显示过度绘制」,优化你的item布局,减少不必要的嵌套和背景,也能提升滚动流畅度。
三、完整修复后的代码示例
CustomAdapter.java
public class CustomAdapter extends RecyclerView.Adapter<CustomViewHolder> { private Context context; private int[] immagineDio; private String[] nomeDio; public CustomAdapter(Context context, int[] immagineDio, String[] nomeDio){ this.context = context; this.immagineDio = immagineDio; this.nomeDio = nomeDio; setHasStableIds(true); // 开启稳定ID } @NonNull @Override public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new CustomViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_item, parent, false)); } @Override public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) { holder.bind(immagineDio[position], nomeDio[position]); } @Override public int getItemCount() { return nomeDio.length; } @Override public long getItemId(int position) { return immagineDio[position]; // 用图片ID作为唯一标识 } }
CustomViewHolder.java(Glide版本)
public class CustomViewHolder extends RecyclerView.ViewHolder { ImageView mFlag; TextView mName; public CustomViewHolder(@NonNull View itemView) { super(itemView); mFlag = itemView.findViewById(R.id.imageView); mName = itemView.findViewById(R.id.textView); } void bind(int imageId, String name) { Glide.with(itemView.getContext()) .load(imageId) .placeholder(R.drawable.placeholder) .error(R.drawable.error) .into(mFlag); mName.setText(name); } }
ListViewActivity.java修复后
public class ListViewActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listview_layout); String[] nomeDei = {"Baldr","Borr","Bragi","Dagr","Dellingr","Eir","Eostre","Forseti","Freya","Freyr","Frigg","Fulla","Gefjun","Gerðr","Gullveig","Heimdallr","Hel","Hermóðr","Höðr","Hœnir","Iðunn","Itreksjóð","Jǫrð","Kvasir","Lóðurr","Lofn","Logi","Lýtir","Máni","Mímir","Móði","Nanna","Njörun","Njörðr","Nótt","Óðr","Rán","Ríg","Sága","Sif","Signe","Sigyn","Sinfjötli","Sjöfn","Skaði","Skirnir","Snotra","Sól","Syn","Thor","Týr","Ullr","Váli","Vár","Ve","Viðarr","Víli","Vör"}; int[] immagineDei = { R.drawable.profilo_baldr, R.drawable.profilo_borr, R.drawable.profilo_bragi, R.drawable.profilo_dagr, R.drawable.profilo_dellingr, R.drawable.profilo_eir, R.drawable.profilo_eostre, R.drawable.profilo_forseti, R.drawable.profilo_freya, R.drawable.profilo_freyr, R.drawable.profilo_frigg, R.drawable.profilo_fulla, R.drawable.profilo_gefjun, R.drawable.profilo_geror, R.drawable.profilo_gullveig, R.drawable.profilo_heimdallr, R.drawable.profilo_hel, R.drawable.profilo_hermoor, R.drawable.profilo_hoor, R.drawable.profilo_hoenir, R.drawable.profilo_iounn, R.drawable.profilo_itreksjoo, R.drawable.profilo_joro, R.drawable.profilo_kvasir, R.drawable.profilo_loourr, R.drawable.profilo_lofn, R.drawable.profilo_logi, R.drawable.profilo_lytir, R.drawable.profilo_mani, R.drawable.profilo_mimir, R.drawable.profilo_modi, R.drawable.profilo_nanna, R.drawable.profilo_njorun, R.drawable.profilo_njoror, R.drawable.profilo_nott, R.drawable.profilo_oor, R.drawable.profilo_ran, R.drawable.profilo_rig, R.drawable.profilo_saga, R.drawable.profilo_sif, R.drawable.profilo_signe, R.drawable.profilo_sigyn, R.drawable.profilo_sinfjotli, R.drawable.profilo_sjofn, R.drawable.profilo_skaoi, R.drawable.profilo_skirnir, R.drawable.profilo_snotra, R.drawable.profilo_sol, R.drawable.profilo_syn, R.drawable.profilo_thor, R.drawable.profilo_tyr, R.drawable.profilo_ullr, R.drawable.profilo_vali, R.drawable.profilo_var, R.drawable.profilo_ve, R.drawable.profilo_vidar, R.drawable.profilo_vili, R.drawable.profilo_vor }; RecyclerView recyclerView = findViewById(R.id.listView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); // 可选:添加分隔线,让列表更清晰 recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); CustomAdapter customAdapter = new CustomAdapter(ListViewActivity.this, immagineDei, nomeDei); recyclerView.setAdapter(customAdapter); } }
内容的提问来源于stack exchange,提问作者Fyd Rose
相关产品推荐
相关产品推荐

