Inconsistency detected in RecyclerView
tamtom opened this issue ยท 25 comments
Hello I have fatal crash in my app reported by Fabric which is incredibly increased after adding a fragment with recycler view that have RealmRecyclerViewAdapter
I'm still not sure if the realm is adapter is the problem or not , I couldn't reproduce the crash I've been playing with my app for two days but nothing happen , and last screen for the user session that reported by Fabric is the screen that have realm adapter
Fatal Exception: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 16(offset:16).state:43
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4957)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4913)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)
at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1193)
at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1043)
at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4357)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:559)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(NativeStart.java)
relam adapter version o.realm:android-adapters:1.4.0
realm version io.realm:realm-gradle-plugin:1.2.0
It seems to be a common problem: http://stackoverflow.com/questions/30220771/recyclerview-inconsistency-detected-invalid-item-position
It's hard to say if it is a Realm related issue without code which shows how you use Realm.
Many suggestions in the stack overflow discussion above. If you still experience the issue, we can reopen it.
for people who faced this problem I find a way to produce it by scrolling the recyclerview then
move to other fragment
here my code for that
`
private void moveToFragment(Fragment fragment, String tag) {
if (isFinishing()) {
return;
}
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
if (fragment.isAdded()) {
fragmentTransaction.show(fragment);
fragment.setUserVisibleHint(true);
} else {
fragmentTransaction.add(R.id.flMain, fragment, tag);
// if (!tag.equals(TabModel.HOME.name()))(
// fragmentTransaction.addToBackStack(tag);
}
// onFragmentVisible(fragment, true);
List<Fragment> fragmentList = fragmentManager.getFragments();
for (int i = 0; i < fragmentList.size(); i++) {
Fragment oldFragment = fragmentList.get(i);
if (oldFragment != null && oldFragment.getTag() != null
&& !oldFragment.getTag().equals(tag)) {
fragmentTransaction.hide(oldFragment);
oldFragment.setUserVisibleHint(false);
onFragmentVisible(oldFragment, false);
}
}
fragmentTransaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
onFragmentVisible(fragment, true);
}`
@kneth I think its not related to realm adapter
I too have the same issue
@babinoclock Can you elaborate? Do you think it is related to Realm?
@kneth as I understood from this discussion:
https://issuetracker.google.com/issues/37030377
(check answers numbers 9, 10 and 12)
It happens because at the same time as user scrolls list Realm adapter in the background update data. And because all this happends in different threads at some point RecyclerView doesn't know what indexes are proper.
Try to remove setStableIds(true) as a temp fix
I moved to setStableIds(true) with my latest release to try to address the issue and the same crash affects 3% of my users instead of 1%, it has actually made it worse.
Before Realm Java 3.1 those kinds of inconsistencies was possible, but in 3.1.0 we changed the notifications so they are emitted immediately on the same thread if a commit is executed there. This should prevent inconsistencies, at least if invalidation in the adapter is done based on RealmChangeListeners.
@KennyGoers You are using 4.1.1 right?
If you still see these kinds of bugs, it could be three reasons:
-
It is a bug in Realm, so a notification is not emitted for some reason.
-
Something is causing a manual redraw while you are changing data on the same thread, but before the the transaction is completed.
-
You are using your own mechanism for invalidating adapters.
We can probably not rule out 1) . I'm currently investigating realm/realm-java#5507 . If that is indeed the same thing you are hitting, then switching to a RealmChangeListener on the Realm itself should fix it (but will mean that the RecyclerView will refresh on any datachange).
With regard to 2) Can you explain your RecyclerView setup in a little more detail?
I'll try to explain my setup in as much detail as I can, maybe you can point out potential holes.I don't think what I'm attempting is an uncommon scenario so might help in general. I have around 24k daily users so the sample size is quite large.
I've wrapped the Realm instances I use to maintain a handle on where they are accessed and consistency in the configuration, I use a single Realm instance for Activities and Fragments and the more general accessor for modification within RxJava background modification on the IO scheduler. Once the query is made it isn't closed. I'm guessing the crashes occur when updated after the initial display.
Within that io scheduler I open a transaction and iterate over a list of items collected from a network call made on another thread, for each item I look to see if it already in the table/object store and either update or add it, usually add, adds are done using realm.insert(). This can often be hundreds of records. When completed I commit the transaction and close that realm.
The recyclerview/adapter is created after the initial results are available and are triggered either by a background job or when reaching the bottom of the list, and the LayoutManager is the GridLayoutManager.
I've seen reference to this crash happening during change notifications happening while the recyclerview is scrolling, in my case this is a possibility as the notifications can come while the user is scrolling through the current contents. This is certainly worth investigating, possibly locking the recyclerview in some way prior to update notifications.
What other info can I get you?
I'm especially interested in:
The recyclerview/adapter is created after the initial results are available and are triggered either by a background job or when reaching the bottom of the list, and the LayoutManager is the GridLayoutManager.
It sounds like you are not using RealmChangeListeners to invalidate the RecyclerViewAdapter, is that correct?
Maybe I wasn't clear, my adapter is derived from the RealmRecyclerViewAdapter and it adds a listener for its notifications of the recyclerview/adapter. I do add a listener to the result set to show and hide the recyclerview if needed for the empty view.
The first query is made AFTER the data exists within the query, but can be later modified in the background by either a query made by the user or by a background Job, but not at the same time. The change in the background is where it seems to be the inconsistency arises.
I don't know the timing of when the notifications are called when the data is updated on a background thread and I'm guessing this issue is related to: https://stackoverflow.com/questions/26827222/inconsistency-detected-in-recyclerview-how-to-change-contents-of-recyclerview-w
@KennyGoers is it possible to share your code of derived RealmRecyclerViewAdapter
? If you always update recycle view in the realm change listener, this error should not happen.
@beeender It could also be realm/realm-java#5507 manifesting here, which could also cause the RecyclerView to crash.
@beeender I can share that code, though I don't want to post it here, how can I get it to you? And I believe from going over this WAY to much that is is related to the notification not being called as @cmelchior is referencing. RecyclerView does not handle data changing and not being notified well.
@KennyGoers you can send it to help@realm.io
This problem happens when the underlying adapterData can not be accessed by the RecyclerView correctly. The reason is for example an already closed Realm instance.
How do you close your Realm instances in the fragements?
Be ensure that you open your Realm instance in onCreateView and close your instance (only once!) in onDestoryView.
See https://realm.io/docs/java/latest/#realm-instance-lifecycle
I also encountered the same issue but get it resolved from
https://readyandroid.wordpress.com/java-lang-indexoutofboundsexception-inconsistency-detected-invalid-item-position-android-recyclerview/
Nice blog with Android tricks: https://readyandroid.wordpress.com/
Is this issue solved.I am facing the same issue.Its happening when I am trying to write something from the background thread and scrolling on UI thread.
From what I can tell it's still there, notifications are not always being propagated to the main thread, but the data gets updated without the recycler view being notified, not sure if anyone is working on it, it was supposed to have been fixed but hasn't been...
@KennyGoers so the auto update should be set to false and handle the recyler notify ourselves?
My issue is solved.As @ChrisBLN mentioned this error was popping due to the usage of closed Realm intsance .
It is not resolved :(