kotlin 如果我在第一个选择器上选择回到上一个选择,NumberPicker将引发ArrayIndexOutOfBoundsException

xienkqul  于 6个月前  发布在  Kotlin
关注(0)|答案(1)|浏览(75)

所以我有两个NumberPicker,第二个选择器的数组将基于第一个选择器的选择。但是在下面的代码中,如果我从5 han中选择4 han,我会遇到以下异常

java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
    at android.widget.NumberPicker.ensureCachedScrollSelectorValue(NumberPicker.java:2010)
    at android.widget.NumberPicker.initializeSelectorWheelIndices(NumberPicker.java:1822)
    at android.widget.NumberPicker.setMaxValue(NumberPicker.java:1520)
    at com.vincent.majcal.ui.picker.PickerFragment.onCreateView$lambda$1(PickerFragment.kt:114)

字符串
下面是这部分的代码,我使用了Bottom Nagivation View Activity模板,并用我自己的用途:修改了它:

package com.vincent.majcal.ui.picker

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.NumberPicker
import android.widget.Switch
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.vincent.majcal.databinding.FragmentPickerTestBinding
import com.vincent.majcal.databinding.FragmentSearchBinding

class PickerFragment : Fragment() {

    private var _binding: FragmentPickerTestBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        val pickerViewModel = ViewModelProvider(this).get(PickerViewModel::class.java)

        _binding = FragmentPickerTestBinding.inflate(inflater, container, false)
        val root: View = binding.root
        val textView: TextView = binding.textSearch
        val firstPicker: NumberPicker = binding.firstPicker
        val secondPicker: NumberPicker = binding.secondPicker
        var fan = "1 han"
        val selections = mapOf(
            "1 han" to arrayOf(
                "30",
                "40",
                "50",
                "60",
                "70",
                "80",
                "90",
                "100",
                "110"
            ),
            "2 han" to arrayOf(
                "20",
                "25",
                "30",
                "40",
                "50",
                "60",
                "70",
                "80",
                "90",
                "100",
                "110"
            ),
            "3 han" to arrayOf(
                "20",
                "25",
                "30",
                "40",
                "50",
                "60",
                "70+",
            ),
            "4 han" to arrayOf(
                "20",
                "25",
                "30",
                "40+",
            ),
            "5 han" to arrayOf(
                "Mangan",
            ),
            "6 ~ 7 han" to arrayOf(
                "Haneman",
            ),
            "8 ~ 10 han" to arrayOf(
                "Baiman",
            ),
            "11 ~ 12 han" to arrayOf(
                "Sanbaiman",
            ),
            "13 han+" to arrayOf(
                "Kazoe Yakuman",
            )
        )

        firstPicker.minValue = 0
        firstPicker.maxValue = selections.keys.size - 1
        firstPicker.displayedValues = selections.keys.toTypedArray()
        firstPicker.wrapSelectorWheel = false

        secondPicker.wrapSelectorWheel = false
        secondPicker.minValue = 0
        // default the max value to the first Picker value set
        var secondDisplayArray = selections[fan]
        if (secondDisplayArray != null) {
            secondPicker.maxValue = secondDisplayArray.size - 1
        }
        secondPicker.displayedValues = secondDisplayArray

        firstPicker.setOnValueChangedListener { picker, oldVal, newVal ->
            run {
                fan = selections.keys.elementAt(newVal)
                secondDisplayArray = selections[fan]
                if (secondDisplayArray != null) {
                    var secondDisplayArraySize: Int = secondDisplayArray!!.size
                    secondPicker.value = 0
                    secondPicker.maxValue = secondDisplayArraySize - 1 //the Logcat show this line cause the exception
                    secondPicker.displayedValues = secondDisplayArray
                }
            }
        }


        pickerViewModel.text.observe(viewLifecycleOwner) {
            textView.text = it
        }
        return root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

iyfamqjs

iyfamqjs1#

尝试更改firstPickerOnValueChangedListener中的操作顺序,以确保displayedValuesmaxValue之前更新。原因是secondPicker.maxValue = secondDisplayArraySize - 1发生在secondPicker.displayedValues = secondDisplayArray之前,因此如果NumberPicker尝试访问基于旧maxValue的值,(在设置新的displayedValues数组之前),这可能会导致超出边界,从而导致ArrayIndexOutOfBoundsException
我也会在更新其他变量之前清除secondPicker.value,以确保它在范围内。

firstPicker.setOnValueChangedListener { picker, oldVal, newVal ->
    run {
        fan = selections.keys.elementAt(newVal)
        secondDisplayArray = selections[fan]
        if (secondDisplayArray != null) {
            var secondDisplayArraySize: Int = secondDisplayArray!!.size
            secondPicker.displayedValues = secondDisplayArray // Update displayedValues first
            secondPicker.maxValue = secondDisplayArraySize - 1 // Then update maxValue
            secondPicker.value = 0 // Ensure value is within bounds
        }
    }
}

字符串

相关问题