Android 检测到RecyclerView错误不一致
虽然我知道类似的问题以前被问过很多次,但我认为我的情况不同。一些答案说错误来自Android库bug,但我使用的API 27可能已经修复了bug 我把我的问题总结成一个最小的项目 首先,我有一个简单的基本适配器类Android 检测到RecyclerView错误不一致,android,android-recyclerview,Android,Android Recyclerview,虽然我知道类似的问题以前被问过很多次,但我认为我的情况不同。一些答案说错误来自Android库bug,但我使用的API 27可能已经修复了bug 我把我的问题总结成一个最小的项目 首先,我有一个简单的基本适配器类 活动类为 在activity类中,我使用了类项和ActivityMainAdapter,它们的实现如下 class Item(val key: Int, val desc: String) class ActivityMainAdapter : EndlessListAdapter&
活动
类为
在activity类中,我使用了类项和ActivityMainAdapter,它们的实现如下
class Item(val key: Int, val desc: String)
class ActivityMainAdapter : EndlessListAdapter<Item>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
VIEW_TYPE_NORMAL -> object : RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.activity_main_viewholder, parent, false)) {}
else -> super.onCreateViewHolder(parent, viewType)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
VIEW_TYPE_NORMAL -> holder.itemView.let {
it.key.text = itemList[position].key.toString()
it.desc.text = itemList[position].desc
}
else -> super.onBindViewHolder(holder, position)
}
}
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean = oldItem.key == newItem.key
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean = oldItem.key == newItem.key && oldItem.desc == newItem.desc
}
我自己解决了。它是由与DiffUtil冲突的空视图引起的 使用DiffUtil类时,当回收器视图上有页眉、页脚或空视图时,这是一个常见错误
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ActivityMain">
<Button
android:id="@+id/button0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="set 0 items" />
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="set 4 items" />
<Button
android:id="@+id/button8"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="set 8 items" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
class ActivityMain : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recycler.layoutManager = LinearLayoutManager(this)
recycler.adapter = ActivityMainAdapter()
RxView.clicks(button0).observeOn(AndroidSchedulers.mainThread()).subscribe {
(recycler.adapter as ActivityMainAdapter).let { adapter ->
adapter.itemList = listOf()
adapter.hasMore = false
}
}
RxView.clicks(button4).observeOn(AndroidSchedulers.mainThread()).subscribe {
(recycler.adapter as ActivityMainAdapter).let { adapter ->
adapter.itemList = listOf(Item(1, "Bob"), Item(2, "Mary"), Item(3, "Ken"), Item(4, "Samantha"))
adapter.hasMore = false
}
}
RxView.clicks(button8).observeOn(AndroidSchedulers.mainThread()).subscribe {
(recycler.adapter as ActivityMainAdapter).let { adapter ->
adapter.itemList = listOf(Item(1, "Jan"), Item(2, "Feb"), Item(3, "Mar"), Item(4, "Apr"), Item(5, "May"), Item(6, "Jun"), Item(7, "Jul"), Item(8, "Aug"))
adapter.hasMore = true
}
}
}
}
class Item(val key: Int, val desc: String)
class ActivityMainAdapter : EndlessListAdapter<Item>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
VIEW_TYPE_NORMAL -> object : RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.activity_main_viewholder, parent, false)) {}
else -> super.onCreateViewHolder(parent, viewType)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
VIEW_TYPE_NORMAL -> holder.itemView.let {
it.key.text = itemList[position].key.toString()
it.desc.text = itemList[position].desc
}
else -> super.onBindViewHolder(holder, position)
}
}
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean = oldItem.key == newItem.key
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean = oldItem.key == newItem.key && oldItem.desc == newItem.desc
}
09-05 17:08:35.787 4087-4087/demo.p1894 E/AndroidRuntime: FATAL EXCEPTION: main
Process: demo.p1894, PID: 4087
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{3c21c3e position=4 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent} android.support.v7.widget.RecyclerView{79870ac VFED..... .F....I. 0,432-1080,489 #7f080071 app:id/recycler}, adapter:demo.p1894.ActivityMainAdapter@f449175, layout:android.support.v7.widget.LinearLayoutManager@a01c50a, context:demo.p1894.ActivityMain@6be630b
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5447)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5629)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5589)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5585)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2231)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1558)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1518)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:610)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3670)
at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3129)
at android.view.View.measure(View.java:18830)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18830)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:139)
at android.view.View.measure(View.java:18830)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.support.v7.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:400)
at android.view.View.measure(View.java:18830)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18830)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18830)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5954)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
at android.view.View.measure(View.java:18830)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2136)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1248)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1484)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1139)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6064)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:860)
at android.view.Choreographer.doCallbacks(Choreographer.java:672)
at android.view.Choreographer.doFrame(Choreographer.java:608)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:846)
at android.os.Handler.handleCallback(Handler.java:742)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5653)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Z