Pager with RecyclerViews containing realmObjects keeps crashing with IllegalState

923 views Asked by At

I have a project using Realm.io for storing entities, this used to work fine, but now I have a fragment or activity containing 3 fragments with Lists of Realm objects.

Whenever I Switched to a page and back to the first one (or whatever just returning to a page). I get the java.lang.IllegalStateException: Illegal State: Row/Object is no longer valid to operate on. Was it deleted?

This seems to occur because the objects are no longer valid. Is there a simple way to detach them or something? Allthough it would be nice if they remain managed since I sometimes want to be able to delete them.

The items are queried from database, when there are not sufficient items they will get loaded from the API. Nothing extremely fancy is being used here, three lists with adapters which load the entities. THe difference per list is a string value status, which says if it's an certain status.

I get the error when I load the item from the Adapter after clicking the list item to show the details:

MyEntity myEntity = (MyEntity) adapter.getItem(position);
intent.putExtra("id", myEntity.getId()) <-- this part will crash it.

with exception:

java.lang.IllegalStateException: Illegal State: Row/Object is no longer valid to operate on. Was it deleted?

I guess it's because it's querying the same type of data on three locations (3 tabs). Though I would expect this not to be a problem since they all have their own adapter and list of items. Fetched from their own instances.

This is the code being called by my "Loader" class which handles the from DB and/or Api fetching.

public void loadResult(List result, boolean isFinished) { //not the best for speed, but at a max of 10 items this is fine to not get duplicates and respect the original order try { for (RealmObject ro : result) { Record r = (Record) ro;

                int itemIndex = items.indexOf(r);
                if (itemIndex > -1) {
                    items.set(itemIndex, r);
                } else {
                    items.add(r);
                }

        }
    } catch (IllegalStateException e) {
        ErrorClass.log(e);
    }

    notifyDataSetChanged();

    setLoading(!isFinished);
    end = result.size() < 10 && isFinished;
}

in short the loader class does this, and it's not a singleton, it's a new instance per Listview (Recycler)

        List result = null;
        if (sortKey != null) {
            result = query.findAllSorted(sortKey, ascending);
        } else {
            result = query.findAll();
        }

        if (result.size() < PAGE_SIZE && retry == 0) {
            isFinished = false;
            retry++;
            getPageFromApi(pageNumber);
        } else if (retry > 0) {
            retry = 0;
        }

        adapter.loadResult(result, isFinished);

The getPageFromApi will result on this code being called again, and existing entities will be replaced in the list, new items added. So no old removed items should exist in the list when clicking them.

I think this might be very specific but there must be a global reason/solution to my problem.

1

There are 1 answers

2
Mathijs Segers On

Stupid me, I wrapped the adding of the new elements in a try catch because of the error before, what was going wrong is pretty simple. In the Loader the items fetched from our API was updating or creating new items. Meaning that those in the list, will be invalid at that point, or at least the pointers to them? Not sure how it works behind the scenes.

What I did to fix it, was loop through all the current items, and check the isValid(), if false the item would be removed. Otherwise I was checking for a new item to be inside the current items List, which would cause the error to occur in the .equals function!

This one thing is something that might be a core error, but I think it's just my error!