java.lang.IndexOutOfBoundsException :尝试从 RecyclerView 中删除 URL 损坏的项目

Posted

技术标签:

【中文标题】java.lang.IndexOutOfBoundsException :尝试从 RecyclerView 中删除 URL 损坏的项目【英文标题】:java.lang.IndexOutOfBoundsException : Trying to remove an item with broken URL from RecyclerView 【发布时间】:2021-12-21 09:36:52 【问题描述】:

我正在使用 Glide 加载 URL 列表,如下所示:

@Override
public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) 
    Glide.with(context)
            .load(arrayList.get(position))
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .error(R.drawable.transparent_icon)
            .override(Constants.THUMBNAIL_SIZE, Constants.THUMBNAIL_SIZE)
            .fitCenter()
            .listener(new RequestListener<Drawable>() 
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) 
                    isBrokenUrl = true;

                  
                    arrayList.remove(holder.getBindingAdapterPosition());  //ISSUE IS HERE
                    notifyItemRangeChanged(holder.getBindingAdapterPosition(), getItemCount());

                    return false;
                

                @Override
                public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) 
                    isBrokenUrl = false;
                    return false;
                
            ).into(holder.image);

    holder.image.setOnClickListener(v -> itemStringClickListener.onItemClicked(arrayList.get(position)));

列表中有一个损坏的 URL,我想从 RecyclerView 中删除带有这些损坏 URL 的项目:

                    arrayList.remove(holder.getBindingAdapterPosition());
                    notifyItemRangeChanged(holder.getBindingAdapterPosition(), getItemCount());

它的工作,但如果我滚动太快,应用程序崩溃:

 com.bumptech.glide.load.engine.CallbackException: Unexpected exception thrown by non-Glide code
        at com.bumptech.glide.load.engine.EngineJob.callCallbackOnLoadFailed(EngineJob.java:175)
        at com.bumptech.glide.load.engine.EngineJob$CallLoadFailed.run(EngineJob.java:402)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:236)
        at android.app.ActivityThread.main(ActivityThread.java:7889)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:600)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
     Caused by: java.lang.ArrayIndexOutOfBoundsException: length=109; index=-1
        at java.util.ArrayList.remove(ArrayList.java:506)
        at maa.utils.adapters.SearchedStickersAdapter$1.onLoadFailed(SearchedStickersAdapter.java:63)
        at com.bumptech.glide.request.SingleRequest.onLoadFailed(SingleRequest.java:683)
        at com.bumptech.glide.request.SingleRequest.onLoadFailed(SingleRequest.java:651)
        at com.bumptech.glide.load.engine.EngineJob.callCallbackOnLoadFailed(EngineJob.java:173)
        at com.bumptech.glide.load.engine.EngineJob$CallLoadFailed.run(EngineJob.java:402) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:236) 
        at android.app.ActivityThread.main(ActivityThread.java:7889) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:600) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967) 

【问题讨论】:

【参考方案1】:

代码失败,因为 getBindingAdapterPosition 返回 -1。该视图持有者未绑定到任何位置。看起来你正在尝试在这里做一些异步的事情。如果是这样,您不应该将视图持有者或其中的任何视图传递给任何回调。相反,您应该在进行异步调用时传递该索引处的位置和/或数据项,而不是在回调期间查询持有者。这是因为绑定可以在那时和回调发生时发生变化。如果您不这样做,即使它“有效”,它也可能对错误的索引执行操作。

实际上,由于您是在 onBindViewHolder 中执行此操作,因此在您使用它的两个地方都将其替换为 position 应该可以正常工作。

【讨论】:

谢谢你的回答,其实我用holder.getBindingAdapterPosition()是因为Android studio显示警告信息是这样的:不要把位置当作固定的;仅立即使用并调用 holder.getAdapterPosition() 稍后查找 但是,我已经用另一种策略解决了这个问题,如果有人遇到同样的问题,我会接受你的回答 他们在不同的背景下谈论。在持有人内部,您不应将位置视为固定 - 您不应假设持有人始终绑定到相同的索引。例如,如果您在那里有一个 onClickEventListener,则应该使用 holder.getBindingAdapterPosition(),否则需要在每次绑定时重新创建它们。您的回调不是在处理持有者,而是在处理原始数据。这意味着他们应该做完全相反的事情。 非常感谢您花时间向我提供这些信息

以上是关于java.lang.IndexOutOfBoundsException :尝试从 RecyclerView 中删除 URL 损坏的项目的主要内容,如果未能解决你的问题,请参考以下文章