airbnb / epoxy

Epoxy is an Android library for building complex screens in a RecyclerView
https://goo.gl/eIK82p
Apache License 2.0
8.51k stars 728 forks source link

BaseEpoxyAdapter crash - npe: Attempt to invoke virtual method 'int androidx.collection.LongSparseArray.size()' on a null object reference #1240

Closed eboudrant closed 3 years ago

eboudrant commented 3 years ago

We noticed this crash in our bug reported and looking at the code BaseEpoxyAdapter I don't understand why/when this could happen. Here the full stacktrace :

java.lang.NullPointerException: Attempt to invoke virtual method 'int androidx.collection.LongSparseArray.size()' on a null object reference
        at com.airbnb.epoxy.BaseEpoxyAdapter.onSaveInstanceState(BaseEpoxyAdapter:231)
        at com.airbnb.epoxy.EpoxyController.onSaveInstanceState(EpoxyController:719)
        at c.n.m.u.h.impl.HFragment.onDestroyView(HFragment:466)
        at androidx.fragment.app.Fragment.performDestroyView(Fragment:3200)
        at androidx.fragment.app.FragmentStateManager.destroyFragmentView(FragmentStateManager:742)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager:346)
        at androidx.fragment.app.SpecialEffectsController$FragmentStateManagerOperation.complete(SpecialEffectsController:745)
        at androidx.fragment.app.SpecialEffectsController$Operation.cancel(SpecialEffectsController:597)
        at androidx.fragment.app.SpecialEffectsController.forceCompleteAllOperations(SpecialEffectsController:332)
        at androidx.fragment.app.SpecialEffectsController.executePendingOperations(SpecialEffectsController:267)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager:2202)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager:2100)
        at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager:1971)
        at androidx.fragment.app.BackStackRecord.commitNow(BackStackRecord:305)
        at c.n.m.u.l.FragmentHelper.replaceFragment(FragmentHelper:375)
        at c.n.m.u.l.FragmentHelper.replaceFragment$default(FragmentHelper:307)
        at c.n.m.u.l.FragmentHelper.removeTopFragment(FragmentHelper:469)
        at c.n.m.u.l.FragmentHelper.removeBackToIndex(FragmentHelper:576)
        at c.n.m.u.l.FragmentHelper.removeAll(FragmentHelper:616)
        at c.n.m.u.h.HActivity.handleNewIntent(HActivity:591)
        at c.n.m.u.h.HActivity.onNewIntent(HActivity:582)
        at c.n.m.u.h.HActivity.onNewIntent(HActivity:569)
        at android.app.Activity.performNewIntent(Activity.java:8222)

Using Epoxy 4.3.1

The only use case viewHolderState could be set to null there is a fail-fast crash, in onRestoreInstanceState(...) :

      viewHolderState = inState.getParcelable(SAVED_STATE_ARG_VIEW_HOLDERS);
      if (viewHolderState == null) {
        throw new IllegalStateException(
            "Tried to restore instance state, but onSaveInstanceState was never called.");
      }
eboudrant commented 3 years ago

Actually I know the issue, we had a try / catch when calling onRestoreInstanceState 🤦