启动MainActivity触发IndexOutOfBoundsException异常求助排查
问题根源与修复方案
核心问题
你错误地将PagingDataAdapter当作普通RecyclerView.Adapter使用:
PagingDataAdapter本身内置了分页数据的管理逻辑,不需要手动维护listStories集合- 你重写的
getItemCount返回自定义列表长度,但Paging库内部逻辑可能在列表为空时仍尝试绑定视图,导致访问listStories[position]触发越界异常
错误触发逻辑
当listStories为空(size=0),但Paging库或RecyclerView的缓存机制触发了onBindViewHolder调用(比如旧视图复用、分页预加载逻辑误判),此时position=0访问空列表就会抛出IndexOutOfBoundsException。
修复步骤
1. 移除自定义数据集合与方法
删除listStories变量和setListStories方法,改用PagingDataAdapter标准API管理数据。
2. 取消重写getItemCount
PagingDataAdapter会自动根据分页数据返回正确条目数,无需手动实现。
3. 修正onBindViewHolder逻辑
通过getItem(position)获取分页数据,同时处理空值(getItem可能返回null):
4. 修复DiffUtil实现
原areItemsTheSame用对象相等判断错误,应使用唯一标识(如id)判断条目是否为同一个:
修改后的完整代码
class MainAdapter: PagingDataAdapter<ListStoryItem, MainAdapter.MyViewHolder>(DIFF_CALLBACK) { private lateinit var onItemClickCallback: OnItemClickCallback class MyViewHolder(var binding: StoryItemBinding) : RecyclerView.ViewHolder(binding.root) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { val binding = StoryItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) return MyViewHolder(binding) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val story = getItem(position) ?: return // 空值直接返回,避免崩溃 val (photoUrl, createdAt, name, description, _) = story holder.binding.tvName.text = name holder.binding.tvStory.text = description val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) val outputFormat = SimpleDateFormat("MMM dd, yyyy - hh:mm a", Locale.getDefault()) val date = inputFormat.parse(createdAt) val formattedDateTimeString = outputFormat.format(date) holder.binding.tvDate.text = formattedDateTimeString Glide.with(holder.itemView.context) .load(photoUrl) .into(holder.binding.imageView2) holder.binding.imageView2.setOnClickListener{ onItemClickCallback.onItemClicked(story) } } fun setOnItemClickCallback(onItemClickCallback: OnItemClickCallback) { this.onItemClickCallback = onItemClickCallback } interface OnItemClickCallback { fun onItemClicked(data: ListStoryItem) } companion object { private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ListStoryItem>() { override fun areItemsTheSame(oldItem: ListStoryItem, newItem: ListStoryItem): Boolean { return oldItem.id == newItem.id // 用唯一ID判断条目是否相同 } override fun areContentsTheSame(oldItem: ListStoryItem, newItem: ListStoryItem): Boolean { return oldItem == newItem // 内容完全相等时返回true } } } }
额外注意事项
- 更新数据时,使用
adapter.submitData(lifecycle, pagingData)提交分页数据,而非自定义方法 - 确保
ListStoryItem是Kotlin数据类(自动实现equals和hashCode),否则areContentsTheSame判断会出错
内容的提问来源于stack exchange,提问作者Bryant Anthony
相关产品推荐
相关产品推荐

