I am getting the above mention crash in a few devices lately, don't know what is triggering it.
Some answers suggest to extend the LayoutManager and silence the exception but I'd rather find a permanent and efficient solution for this, some suggest to clear the list in the adapter which I'm doing but still a crash.
Here's the Adapter class -
class Adapter(private val adapterType: Int, private val clickListener: GalleryHolder.ClickListener) : SelectableAdapter<Adapter.GalleryHolder>() {
val objectArrayList: ArrayList<String> = ArrayList()
private var emptyView: View? = null
companion object {
const val IMAGE = 0
const val VIDEO = 1
}
fun addAll(items: ArrayList<String>) {
objectArrayList.addAll(items)
notifyItemRangeInserted(0, objectArrayList.size)
}
fun clear() {
val size = objectArrayList.size
notifyItemRangeRemoved(0, size)
objectArrayList.clear()
}
override fun getItemCount(): Int {
return objectArrayList.size
}
fun setEmptyView(emptyView: View) {
this.emptyView = emptyView
}
fun toogleEmptyView() {
if (objectArrayList.size == 0) emptyView!!.visibility = View.VISIBLE
else emptyView!!.visibility = View.GONE
}
fun removeItems(positions: MutableList<Int>) {
positions.sortWith(Comparator { lhs, rhs -> rhs!! - lhs!! })
while (positions.isNotEmpty()) {
if (positions.size == 1) {
removeItem(positions[0])
positions.removeAt(0)
} else {
var count = 1
while (positions.size > count && positions[count] == positions[count - 1] - 1)
++count
if (count == 1)
removeItem(positions[0])
else
removeRange(positions[count - 1], count)
if (count > 0) positions.subList(0, count).clear()
}
}
toogleEmptyView()
}
private fun removeRange(positionStart: Int, itemCount: Int) {
for (i in 0 until itemCount) objectArrayList.removeAt(positionStart)
notifyItemRangeRemoved(positionStart, itemCount)
}
private fun removeItem(position: Int) {
objectArrayList.removeAt(position)
notifyItemRemoved(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GalleryHolder {
var layout = R.layout.item
if (adapterType == VIDEO) layout = R.layout.item_video
val view = LayoutInflater.from(parent.context).inflate(layout, parent, false)
return GalleryHolder(view)
}
override fun onBindViewHolder(holder: GalleryHolder, position: Int) {
if (adapterType == VIDEO)
Glide.with(holder.img)
.asBitmap()
.apply(RequestOptions()
.frame(TimeUnit.SECONDS.toMicros(2))
.diskCacheStrategy(DiskCacheStrategy.ALL))
.load(objectArrayList[holder.adapterPosition])
.transition(BitmapTransitionOptions.withCrossFade())
.into(holder.img)
else
Glide.with(holder.img)
.asBitmap()
.apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
.load(objectArrayList[holder.adapterPosition])
.transition(BitmapTransitionOptions.withCrossFade())
.into(holder.img)
// Highlight the item if it's selected
holder.selectedOverlay.setBackgroundColor(ColorUtils.setAlphaComponent(HelperMethods.getPrimaryColor(holder.selectedOverlay.context), 175))
holder.selectedOverlay.visibility = if (isSelected(holder.adapterPosition)) View.VISIBLE else View.INVISIBLE
holder.itemView.setOnClickListener { clickListener.onItemClicked(holder.adapterPosition) }
holder.itemView.setOnLongClickListener { clickListener.onItemLongClicked(holder.adapterPosition) }
}
class GalleryHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal val img: ImageView = itemView.findViewById(R.id.img)
internal val selectedOverlay: RelativeLayout = itemView.findViewById(R.id.parent)
interface ClickListener {
fun onItemClicked(position: Int)
fun onItemLongClicked(position: Int): Boolean
}
}
}
Following is the stacktrace -
Fatal Exception: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{41bc02f0 position=116 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached not recyclable(1) no parent} androidx.recyclerview.widget.RecyclerView{41dc3c18 VFED.... .F....ID 0,0-480,606 #7f090125 app:id/recycler_view}, adapter:c.g.a.b.a@41df0ba8, layout:androidx.recyclerview.widget.GridLayoutManager@41d8ca08, context:com.example.MainActivity@41cc4090
at androidx.recyclerview.widget.RecyclerView$Recycler.setViewCacheExtension(RecyclerView.java:79)
at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition + 5901(RecyclerView.java:5901)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline + 6084(RecyclerView.java:6084)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition + 6044(RecyclerView.java:6044)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition + 6040(RecyclerView.java:6040)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next + 2303(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.GridLayoutManager.layoutChunk + 561(GridLayoutManager.java:561)
at androidx.recyclerview.widget.LinearLayoutManager.onAnchorReady(LinearLayoutManager.java:105)
at androidx.recyclerview.widget.LinearLayoutManager.fill + 1587(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren + 665(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren + 170(GridLayoutManager.java:170)
at androidx.recyclerview.widget.RecyclerView.onScrollStateChanged(RecyclerView.java:74)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1 + 4014(RecyclerView.java:4014)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout + 3778(RecyclerView.java:3778)
at androidx.recyclerview.widget.RecyclerView.onLayout + 4333(RecyclerView.java:4333)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.RelativeLayout.onLayout + 1055(RelativeLayout.java:1055)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onLayout + 625(SwipeRefreshLayout.java:625)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.FrameLayout.layoutChildren + 453(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout + 388(FrameLayout.java:388)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at androidx.viewpager.widget.ViewPager.onLayout + 1775(ViewPager.java:1775)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.LinearLayout.setChildFrame + 1677(LinearLayout.java:1677)
at android.widget.LinearLayout.layoutVertical + 1531(LinearLayout.java:1531)
at android.widget.LinearLayout.onLayout + 1440(LinearLayout.java:1440)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at androidx.drawerlayout.widget.DrawerLayout.onLayout + 1231(DrawerLayout.java:1231)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.FrameLayout.layoutChildren + 453(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout + 388(FrameLayout.java:388)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.FrameLayout.layoutChildren + 453(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout + 388(FrameLayout.java:388)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.FrameLayout.layoutChildren + 453(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout + 388(FrameLayout.java:388)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.LinearLayout.setChildFrame + 1677(LinearLayout.java:1677)
at android.widget.LinearLayout.layoutVertical + 1531(LinearLayout.java:1531)
at android.widget.LinearLayout.onLayout + 1440(LinearLayout.java:1440)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.widget.FrameLayout.layoutChildren + 453(FrameLayout.java:453)
at android.widget.FrameLayout.onLayout + 388(FrameLayout.java:388)
at android.view.View.layout + 15602(View.java:15602)
at android.view.ViewGroup.layout + 4880(ViewGroup.java:4880)
at android.view.ViewRootImpl.performLayout + 2256(ViewRootImpl.java:2256)
at android.view.ViewRootImpl.performTraversals + 2010(ViewRootImpl.java:2010)
at android.view.ViewRootImpl.doTraversal + 1234(ViewRootImpl.java:1234)
at android.view.ViewRootImpl$TraversalRunnable.run + 6301(ViewRootImpl.java:6301)
at android.view.Choreographer$CallbackRecord.run + 813(Choreographer.java:813)
at android.view.Choreographer.doCallbacks + 613(Choreographer.java:613)
at android.view.Choreographer.doFrame + 583(Choreographer.java:583)
at android.view.Choreographer$FrameDisplayEventReceiver.run + 799(Choreographer.java:799)
at android.os.Handler.handleCallback + 733(Handler.java:733)
at android.os.Handler.dispatchMessage + 95(Handler.java:95)
at android.os.Looper.loop + 146(Looper.java:146)
at android.app.ActivityThread.main + 5511(ActivityThread.java:5511)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke + 515(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run + 1283(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main + 1099(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(NativeStart.java)
Any help would be appreciated.
The error appears, because the system is trying to find a list element, which is not existent anymore, because you removed it in an earlier loop iteration.
Make sure you do not remove elements from a list while you are still iterating over list items or accessing the list.
Just create a separate list for the elements you want to remove and remove them AFTER the loops are complete.
You are trying to notify removed items which are not yet removed.
You need to first clear your list objectArrayList.clear()
and then notifyItemRangeRemoved(0, size)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With