酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

AndroidでNumberPickerの表示項目数を変更する前にはsetDisplayedValues(null)で初期化する

ここ最近Androidアプリネタが続いていますが、この土日悩んだアプリがクラッシュしてしまう件についてメモしておきます。

やりたいこと

日付ごとに異なった時刻を設定できるNumberPickerがありました。イメージがわきにくいと思うので、別の例で……都道府県がいくつか並んでいて選択した都道府県によって、そこからさらに市区町村を選択できるような挙動になっていました。

ここまで書いてから、NumberPickerの問題で悩んでいたのになんで都道府県を例に出しているんだろう…まぁいいや。

指定可能な項目数が変わったらNumberPickerがクラッシュしてしまう

日付を変更すると設定可能な時刻が変わるのですが、時刻を変更した時点…具体的に書くと指定可能な項目数が変わった時点でArrayIndexOutOfBoundsExceptionの例外が発生します。

E/AndroidRuntime: FATAL EXCEPTION: main
   java.lang.ArrayIndexOutOfBoundsException: length=15; index=20
       at android.widget.NumberPicker.ensureCachedScrollSelectorValue(NumberPicker.java:1825)
       at android.widget.NumberPicker.initializeSelectorWheelIndices(NumberPicker.java:1640)
       at android.widget.NumberPicker.setMaxValue(NumberPicker.java:1445)

NumberPicker#setMaxValue()を実行すると、クラッシュする時とクラッシュしない時がありました。コードは下記のようになっています。

picker.setMinValue(0);
picker.setMaxValue(newMaxValue);
picker.setDisplayedValues(values);

表示項目DisplayedValuesの数と最大数newMaxValueの数がマッチしていない場合に問題が起こることが確認できました。

setValue(0)で最小値を設定しているので min 〜 maxの範囲内に収まっているのになんで範囲外の扱いになるんだろう?と悩んでしまいました。

解決策

少し違和感があるのですが、NumberPicker#setMaxValue()を指定する直前にNumberPicker#setDisplayedValues(null)で初期化しておくことで、アプリはクラッシュしなくなりました。

picker.setDisplayedValues(null);
picker.setMinValue(0);
picker.setMaxValue(newMaxValue);
picker.setDisplayedValues(values);