Как сбросить данные NumberPicker

Я использую два NumberPicker для отображения провинции (mProvincePicker) и город (mCityPicker) данные в моем приложении. Когда пользователь изменяет данные провинции, данные города должны быть изменены соответствующим образом. Я сбросил mCityPicker данные в NumberPicker.onValueChange(NumberPicker picker, int oldVal, int newVal), Но это не работает хорошо и java.lang.ArrayIndexOutOfBoundsException вылетает приложение

Вот мой код:

public class AreaPickerDialog extends Dialog implements OnValueChangeListener, OnClickListener {
    static final String TAG = "AreaPickerDialog";

    private NumberPicker mProvincePicker;
    private NumberPicker mCityPicker;
    private Button mCancelBtn;
    private Button mOKBtn;

    private AreaUtil mAreaUtil;
    private List<Area> mProvinces;
    private int mAreaId;
    private int mProvinceId;
    private Handler mHandler;

    public AreaPickerDialog(Context context, Handler handler, int areaId) {
        super(context);
        mAreaUtil = AreaUtil.getInstance();
        mProvinces = mAreaUtil.getProvinceList();
        mAreaId = areaId;
        mProvinceId = mAreaUtil.getProvinceIdByAreaId(areaId);
        mHandler = handler;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dialog_area_picker);
        mProvincePicker = (NumberPicker) findViewById(R.id.np_province);
        mCityPicker = (NumberPicker) findViewById(R.id.np_city);
        mCancelBtn = (Button) findViewById(R.id.btn_cancel);
        mOKBtn = (Button) findViewById(R.id.btn_ok);

        initProvinceData();

        mProvincePicker.setOnValueChangedListener(this);
        mCityPicker.setOnValueChangedListener(this);
        mCancelBtn.setOnClickListener(this);
        mOKBtn.setOnClickListener(this);
    }

    private void initProvinceData() {
        if (mProvinces != null && mProvinces.size() > 0) {
            String[] provinceNames = new String[mProvinces.size()];
            for (int i = 0; i < provinceNames.length; i++) {
                provinceNames[i] = mProvinces.get(i).getProvincename();
            }
            mProvincePicker.setDisplayedValues(provinceNames );
            mProvincePicker.setMinValue(1);
            mProvincePicker.setMaxValue(mProvinces.size());
        }
        mProvincePicker.setValue(mProvinceId);
        initCityData(mProvincePicker.getValue());
    }

    private void initCityData(int provinceId) {
        List<Arealist> cities = mAreaUtil.getCityListOfProvince(provinceId);
        if (cities != null && cities.size() > 0) {
            try {
                int min = Integer.parseInt(cities.get(0).getAreaid());
                int max = Integer.parseInt(cities.get(cities.size() -1).getAreaid());
                String[] cityNames = new String[cities.size()];
                for (int i = 0; i < cityNames.length; i++) {
                    cityNames[i] = cities.get(i).getName();
                }
                mCityPicker.setValue(0);
                mCityPicker.setDisplayedValues(cityNames);
                mCityPicker.setMinValue(min);
                mCityPicker.setMaxValue(max);
            } catch (NumberFormatException e) {
                ILog.e(TAG, e.getMessage(), e);
            }
        }
    }

    @Override
    public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
        if (mProvincePicker.equals(picker)) {
            initCityData(mProvincePicker.getValue());
        } else if (mCityPicker.equals(picker)) {
            mAreaId = mCityPicker.getValue();
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_cancel:
            dismiss();
            break;

        case R.id.btn_ok:
            Message msg = mHandler.obtainMessage(MineActivity.MSG_UPDATE_AREA);
            msg.arg1 = mAreaId;
            msg.sendToTarget();
            dismiss();
            break;

        default:
            break;
        }
    }
} 

И трассировка ошибок logcat:

12-30 23:09:26.560: E/InputEventReceiver(5620): Exception dispatching input event.
12-30 23:09:26.560: W/dalvikvm(5620): threadid=1: thread exiting with uncaught exception (group=0x41ddf438)
12-30 23:09:26.580: E/AndroidRuntime(5620): FATAL EXCEPTION: main
12-30 23:09:26.580: E/AndroidRuntime(5620): java.lang.ArrayIndexOutOfBoundsException: length=14; index=15
12-30 23:09:26.580: E/AndroidRuntime(5620):     at net.simonvt.numberpicker.NumberPicker.updateInputTextView(NumberPicker.java:1840)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at net.simonvt.numberpicker.NumberPicker.setDisplayedValues(NumberPicker.java:1423)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at com.meishai.app.dialog.AreaPickerDialog.initCityData(AreaPickerDialog.java:88)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at com.meishai.app.dialog.AreaPickerDialog.onValueChange(AreaPickerDialog.java:100)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at net.simonvt.numberpicker.NumberPicker.notifyChange(NumberPicker.java:1855)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at net.simonvt.numberpicker.NumberPicker.setValueInternal(NumberPicker.java:1641)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at net.simonvt.numberpicker.NumberPicker.scrollBy(NumberPicker.java:1106)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at net.simonvt.numberpicker.NumberPicker.onTouchEvent(NumberPicker.java:886)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at android.view.View.dispatchTouchEvent(View.java:7127)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2170)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1905)
12-30 23:09:26.580: E/AndroidRuntime(5620):     at net.simonvt.numberpicker.NumberPicker.dispatchTouchEvent(NumberPicker.java:944)
    ....

Я сбрасываю minValue,maxValue and DisplayedValues сбросить NumberPicker данные и не работают, так что это правильный путь?

4 ответа

Решение

Хорошо, я смотрю на исходный код NumberPicker.java, обнаружив, что он будет пересчитывать данные и обновлять пользовательский интерфейс в setMinValue(int minValue) а также setMaxValue(int minValue), Когда установлено новое minValue, оно будет вычисляться с использованием нового minValue и старого maxValue, после чего произошла ошибка.

Итак, я модифицирую немного NumberPicker: установить значение только в setMinValue(int minValue) а также setMaxValue(int maxValue)и обновить пользовательский интерфейс в setDisplayedValues(String[] displayedValues), Когда данные NumberPicker изменилось, просто сбросьте значения minValue, maxVaule и отображаемые значения. Обратите внимание, что setDisplayedValues(String[] displayedValues) ДОЛЖЕН быть вызван в конце концов.

Вот что я модифицировал:

NumberPicker.java:

public void setMinValue(int minValue) {
    if (mMinValue == minValue) {
        return;
    }
    if (minValue < 0) {
        throw new IllegalArgumentException("minValue must be >= 0");
    }
    mMinValue = minValue;
    if (mMinValue > mValue) {
        mValue = mMinValue;
    }
    //boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
    //setWrapSelectorWheel(wrapSelectorWheel);
    //initializeSelectorWheelIndices();
    //updateInputTextView();
    //tryComputeMaxWidth();
    invalidate();
}

public void setMaxValue(int maxValue) {
    if (mMaxValue == maxValue) {
        return;
    }
    if (maxValue < 0) {
        throw new IllegalArgumentException("maxValue must be >= 0");
    }
    mMaxValue = maxValue;
    if (mMaxValue < mValue) {
        mValue = mMaxValue;
    }
    //boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
    //setWrapSelectorWheel(wrapSelectorWheel);
    //initializeSelectorWheelIndices();
    //updateInputTextView();
    //tryComputeMaxWidth();
    invalidate();
}

public void setDisplayedValues(String[] displayedValues) {
    if (mDisplayedValues == displayedValues) {
        return;
    }
    mDisplayedValues = displayedValues;
    if (mDisplayedValues != null) {
        // Allow text entry rather than strictly numeric entry.
        mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT
                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
    } else {
        mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
    }
    boolean wrapSelectorWheel = mMaxValue - mMinValue > mSelectorIndices.length;
    setWrapSelectorWheel(wrapSelectorWheel);
    updateInputTextView();
    initializeSelectorWheelIndices();
    tryComputeMaxWidth();
}

AreaPickerDialog.java:

private void initCityData(int provinceId) {
    List<Arealist> cities = mAreaUtil.getCityListOfProvince(provinceId);
    if (cities != null && cities.size() > 0) {
        try {
            int min = Integer.parseInt(cities.get(0).getAreaid());
            int max = Integer.parseInt(cities.get(cities.size() -1).getAreaid());
            String[] cityNames = new String[cities.size()];
            for (int i = 0; i < cityNames.length; i++) {
                cityNames[i] = cities.get(i).getName();
            }
            mCityPicker.setMinValue(min);
            mCityPicker.setMaxValue(max);
            mCityPicker.setDisplayedValues(cityNames);
        } catch (NumberFormatException e) {
            ILog.e(TAG, e.getMessage(), e);
        }
    }
}

Это уродливое, но рабочее решение.

Проверить на звонок setDisplayedValues(null) до setMaxValue в onClick.

Ссылка: /questions/40519192/vyibor-nomera-s-dinamicheskim-spiskom/40519198#40519198

У меня та же проблема, и я исправил ее без изменений NumberPicker.java, Вот код для вашей справки.

private void initCityData(int provinceId) {
        List<Arealist> cities = mAreaUtil.getCityListOfProvince(provinceId);
        if (cities != null && cities.size() > 0) {
            try {
                int min = Integer.parseInt(cities.get(0).getAreaid());
                int max = Integer.parseInt(cities.get(cities.size() -1).getAreaid());
                String[] cityNames = new String[cities.size()];
                for (int i = 0; i < cityNames.length; i++) {
                    cityNames[i] = cities.get(i).getName();
                }
                int maxV = mCityPicker.getMaxValue();
                if (max> maxV){ 
                    mCityPicker.setMinValue(min);
                    mCityPicker.setValue(0);
                    mCityPicker.setDisplayedValues(cityNames);
                    mCityPicker.setMaxValue(max);
                }else{
                    mCityPicker.setMinValue(min);
                    mCityPicker.setValue(0);
                    mCityPicker.setMaxValue(max);
                    mCityPicker.setDisplayedValues(cityNames);
                }

            } catch (NumberFormatException e) {
                ILog.e(TAG, e.getMessage(), e);
            }
        }
    }

Просто установите для displayValues ​​значение null перед сбросом средства выбора номера, как показано ниже:

 pickerWard.displayedValues = null

 pickerWard.maxValue = values.size - 1
 pickerWard.displayedValues = values

Ищем код используемого NumberPicker:

private boolean updateInputTextView() {
/*
* If we don't have displayed values then use the current number else
* find the correct value in the displayed values for the current
* number.
*/
        String text = (mDisplayedValues == null) ? formatNumber(mValue)
                : mDisplayedValues[mValue - mMinValue];

вы можете увидеть, что он использует mMinValue, прежде чем вызывать setMinValue.

Попробуйте установить minValue и maxValue, прежде чем устанавливать отображаемые значения.

Другие вопросы по тегам