RecyclerView报Do not treat position as fixed 用getAdapterPosition仍点击崩溃怎么解决
Android RecyclerView适配器点击崩溃问题解决方案
崩溃原因
holder.getAdapterPosition()在ViewHolder已被回收、对应条目已被移除但列表未完成刷新的场景下,会返回常量RecyclerView.NO_POSITION(值为-1)- 直接将无效位置传给PlayerActivity后,后续从音乐列表取值时会触发数组下标越界异常,导致崩溃
修复方案
1. 核心修复:增加位置有效性判断
点击事件触发后先校验获取到的位置是否合法,仅合法位置才执行后续跳转逻辑
2. 性能优化:迁移点击事件位置
将点击事件从onBindViewHolder移到ViewHolder构造方法中,避免每次条目复用时重复创建点击事件实例,减少不必要的内存开销
完整修改后代码
MusicAdapter(Context mcontext, ArrayList<MusicFile> mfiles) { this.mfiles = mfiles; this.mcontext = mcontext; } @Override // androidx.recyclerview.widget.RecyclerView.Adapter public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new MyViewHolder(LayoutInflater.from(this.mcontext).inflate(R.layout.music_items, parent, false)); } public void onBindViewHolder(final MyViewHolder holder, int position) { holder.file_name.setText(this.mfiles.get(position).getTitle()); byte[] image = getAlbumArt(this.mfiles.get(position).getPath()); if (image != null) { Glide.with(this.mcontext).asBitmap().load(image).into(holder.album_art); } else { Glide.with(this.mcontext).load(R.drawable.ic_launcher_background).into(holder.album_art); } } @Override // androidx.recyclerview.widget.RecyclerView.Adapter public int getItemCount() { return this.mfiles.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { ImageView album_art; TextView file_name; LinearLayout linearLayout; public MyViewHolder(View itemView) { super(itemView); this.file_name = (TextView) itemView.findViewById(R.id.music_file_name); this.album_art = (ImageView) itemView.findViewById(R.id.music_img); linearLayout = itemView.findViewById(R.id.linear_layout); // 点击事件移到此处 itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int adapterPosition = getAdapterPosition(); // 增加有效性判断,过滤无效位置 if (adapterPosition != RecyclerView.NO_POSITION) { Intent intent = new Intent(mcontext, PlayerActivity.class); intent.putExtra("position", adapterPosition); mcontext.startActivity(intent); } } }); } } private byte[] getAlbumArt(String uri) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(uri); byte[] art = retriever.getEmbeddedPicture(); retriever.release(); return art; }
额外注意事项
- 如果列表存在增删改操作,优先使用
notifyItemInserted、notifyItemRemoved、notifyItemChanged等定向刷新方法,不要全量调用notifyDataSetChanged,可保证getAdapterPosition返回值的准确性 - 不要在
onBindViewHolder之外的场景使用onBindViewHolder传入的position参数,所有延迟调用场景(比如点击、异步回调)统一使用getAdapterPosition获取实时位置
内容的提问来源于stack exchange,提问作者sathish kumar
相关产品推荐
相关产品推荐

