realm / realm-android-adapters

Adapters for combining Realm Java with Android UI components and framework classes
realm.io
Apache License 2.0
414 stars 134 forks source link

Inconsistency detected in RecyclerView #76

Closed tamtom closed 6 years ago

tamtom commented 7 years ago

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

kneth commented 7 years ago

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.

kneth commented 7 years ago

Many suggestions in the stack overflow discussion above. If you still experience the issue, we can reopen it.

tamtom commented 7 years ago

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

babinoclock commented 7 years ago

I too have the same issue

kneth commented 7 years ago

@babinoclock Can you elaborate? Do you think it is related to Realm?

dGorod commented 7 years ago

@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.

muruthi commented 7 years ago

Try to remove setStableIds(true) as a temp fix

KennyGoers commented 6 years ago

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.

cmelchior commented 6 years ago

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:

1) It is a bug in Realm, so a notification is not emitted for some reason.

2) Something is causing a manual redraw while you are changing data on the same thread, but before the the transaction is completed.

3) You are using your own mechanism for invalidating adapters.

We can probably not rule out 1) . I'm currently investigating https://github.com/realm/realm-java/issues/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?

KennyGoers commented 6 years ago

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?

cmelchior commented 6 years ago

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?

KennyGoers commented 6 years ago

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

EMIN3M1986 commented 6 years ago

Read it: https://stackoverflow.com/a/47324896/4468776

beeender commented 6 years ago

@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.

cmelchior commented 6 years ago

@beeender It could also be https://github.com/realm/realm-java/issues/5507 manifesting here, which could also cause the RecyclerView to crash.

KennyGoers commented 6 years ago

@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.

beeender commented 6 years ago

@KennyGoers you can send it to help@realm.io

ChrisKruegerDev commented 6 years ago

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

KennyGoers commented 6 years ago

I open the UI instance only one time and never close it! From what I remember the event fires on the realm event listener, but not the query listener so how would that compare to closing the instance?

On Sun, Nov 19, 2017 at 9:05 AM chrisbln notifications@github.com wrote:

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

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/realm/realm-android-adapters/issues/76#issuecomment-345523264, or mute the thread https://github.com/notifications/unsubscribe-auth/AAaOPJBaC9H6_za5TetXJzONxqfdnEsHks5s4EOugaJpZM4Ldcem .

d-rahul commented 6 years ago

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/

SuhasTS commented 6 years ago

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.

KennyGoers commented 6 years ago

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

SuhasTS commented 6 years ago

@KennyGoers so the auto update should be set to false and handle the recyler notify ourselves?

SuhasTS commented 6 years ago

My issue is solved.As @chrisbln mentioned this error was popping due to the usage of closed Realm intsance .

gelbertgel commented 6 years ago

It is not resolved :(