更新(2018/06/29)
サポートライブラリ25.3.1にてこの問題が解消していたらしい。
軽く再現してみたけど、クラッシュしなかった。
https://issuetracker.google.com/issues/37122716#comment23
現象
特定画面の画面遷移時に、NullPointerExceptionでアプリが落ちることがある。
開発向けオプションの「アクティビティを保持しない」設定ONで100%再現する。
java.lang.RuntimeException: Unable to start activity ComponentInfo{XXXX/MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
at android.view.View.dispatchRestoreInstanceState(View.java:15746)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3231)
at android.view.View.restoreHierarchyState(View.java:15729)
at android.support.design.internal.NavigationMenuPresenter$NavigationMenuAdapter.restoreInstanceState(NavigationMenuPresenter.java:585)
at android.support.design.internal.NavigationMenuPresenter.onRestoreInstanceState(NavigationMenuPresenter.java:180)
at android.support.v7.view.menu.MenuBuilder.dispatchRestoreInstanceState(MenuBuilder.java:349)
at android.support.v7.view.menu.MenuBuilder.restorePresenterStates(MenuBuilder.java:361)
at android.support.design.widget.NavigationView.onRestoreInstanceState(NavigationView.java:192)
at android.view.View.dispatchRestoreInstanceState(View.java:15751)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3231)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3237)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3237)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3237)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3237)
at android.view.View.restoreHierarchyState(View.java:15729)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2106)
at android.app.Activity.onRestoreInstanceState(Activity.java:1047)
at android.app.Activity.performRestoreInstanceState(Activity.java:1002)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1174)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2638)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
原因
条件
- NavigationViewを使っている画面
- menuにactionLayoutを使っている
- プログラム側でactionLayoutを使っているitemをVisible = GONEにしている状態
この条件下で、この画面から他の画面へ遷移し、再び戻ろうと画面遷移をすると落ちる
どこが悪さしている
画面を離れる際に、NavigationViewを使っている画面では
NavigationMenuPresenter.createInstanceStateが実行される。
そこでは、menuの各itemに対してActionViewの状態保存が実行されるが、
そのときにVisible=GONEのitemは状態保存の対象外になってしまう。
その後、戻ってくる時に
NavigationMenuPresenter.onRestoreInstanceStateで、menuのActionViewを復元しようとするが、保存できていないitemの状態を取得しようとして失敗して落ちている
「itemはあるがその状態はnull」ってなってしまう
解決法
Activity側で、画面から離れるときはVisible = VISIBLEにする
itemを隠したいときはonResumeとかで再設定する
まとめ
- (たぶん)AndroidSupportライブラリ側のバグ
- NavigationView+ActionLayout+Visibleが重なると発生する
- 一時的に表示させてから画面遷移すると防げる