检测到不一致。无效的视图支架适配器positionViewHolder

时间:2019-07-03 07:15:17

标签: android kotlin android-recyclerview recycler-adapter

我最近在一些设备中遇到了上述崩溃,不知道是什么触发了它。

一些答案​​建议扩展LayoutManager并使异常保持沉默,但我宁愿为此找到一个永久有效的解决方案,一些建议清除我正在做的适配器列表,但仍然会崩溃。

这是Adapter类-

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
        }
    }
}

以下是堆栈跟踪-

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)

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

出现此错误是因为系统试图查找不再存在的list元素,因为您已在较早的循环迭代中将其删除。

确保仍在遍历列表项或访问列表时不要从列表中删除元素。

只需为要删除的元素创建一个单独的列表,然后在循环完成后将其删除。

答案 1 :(得分:0)

您正在尝试通知尚未删除的已删除项目。

您需要先清除列表 objectArrayList.clear(),然后是 notifyItemRangeRemoved(0, size)