LoginSignup
1
0

More than 5 years have passed since last update.

画面遷移時にSparseArray.get(int)がnullで落ちるときの原因

Last updated at Posted at 2017-01-26

更新(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が重なると発生する
  • 一時的に表示させてから画面遷移すると防げる

リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0