Можно ли вызвать метод onCheckedChanged без взаимодействия?

У меня есть пользовательский ListView, когда при нажатии на элемент запускается новый Activity. В каждой строке ListView есть CheckBox и TextView.

Это метод getView из моего пользовательского ListView:

public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.puzzles_row, null);
        }
        ListedPuzzle lp = items.get(position);
        if (lp != null) {
            TextView title = (TextView) v.findViewById(R.id.listTitles);
            title.setText(lp.getTitle());
            CheckBox star = (CheckBox) v.findViewById(R.id.star_listed);
            star.setChecked(lp.isStarred());
            star.setTag(new Integer(position));

            star.setOnCheckedChangeListener(new OnCheckedChangeListener() {

                public void onCheckedChanged(CompoundButton buttonView,
                        boolean isChecked) {
                    Integer realPosition = (Integer) buttonView.getTag();
                    ListedPuzzle obj = items.get(realPosition);
                    starListedPuzzle(obj.getId(), isChecked);
                }
            });

        }
        return v;

    }

onCheckedChanged вызывается при возврате из другого Activty, без возможного взаимодействия с пользователем для фактической проверки чего-либо.

Дело в том, что раньше работало нормально и особо ничего не меняло. Я читал, что это ошибка, но не могу поверить в это.

Он всегда вызывает метод для одних и тех же двух элементов ListView. Могут ли они быть как-то установлены на checkedChange=true?


person eskalera    schedule 18.05.2012    source источник


Ответы (4)


У меня такое ощущение, что это происходит в методе onRestoreInstanceState. Android автоматически восстанавливает состояние большинства Views в вашей деятельности, когда она приостанавливается и возобновляется. При возобновлении кажется, что восстанавливается отмеченное состояние ваших CheckBox объектов, которое запускает onCheckedChanged. Попробуйте сделать это в своем Activity и дайте мне знать, решит ли это вашу проблему:

private boolean mRestoringInstanceState;

@Override
protected void onRestoreInstanceState( Bundle savedInstanceState ) {

    mRestoringInstanceState = true;
    super.onRestoreInstanceState( savedInstanceState );
    mRestoringInstanceState = false;
}

Затем измените свой метод onCheckChanged следующим образом:

public void onCheckedChanged(CompoundButton buttonView,
        boolean isChecked) {

    if(!mRestoringInstanceState) {
        Integer realPosition = (Integer) buttonView.getTag();
        ListedPuzzle obj = items.get(realPosition);
        starListedPuzzle(obj.getId(), isChecked);
    }
}

Изменить: Вероятно, лучшим / более простым решением было бы назначить слушателя в методе onResume, поскольку он вызывается после onRestoreInstanceState. Обратите внимание, что вы не реализуете ничего из вышеперечисленного, если используете это решение:

@Override
protected void onResume() {

    super.onResume();
    CheckBox star = (CheckBox) v.findViewById(R.id.star_listed);
    star.setOnCheckedChangeListener(new OnCheckedChangeListener() {

        public void onCheckedChanged(CompoundButton buttonView,
                boolean isChecked) {
            // onCheckedChanged implementation
        }
    });
}

Edit2: только что понял, что вы делаете это в Adapter. Возможно, это не связано с onRestoreInstanceState, но я думаю, что вижу проблему. Вы повторно используете View в Adapter, что хорошо, но вы устанавливаете для star значение check перед установкой слушателя. Проблема в том, что star уже имеет слушателя с последнего раза, когда он проходил через метод getView. Прежде чем позвонить star.setChecked(), позвоните star.setOnCheckedChangedListener(null) и посмотрите, решит ли это вашу проблему.

person Jason Robinson    schedule 18.05.2012
comment
Вы абсолютно правы! Однако теперь нажатие на мой CheckBox, конечно же, ничего не дает. - person eskalera; 18.05.2012
comment
Так должно быть, если вы устанавливаете mRestoringInstanceState обратно на false после того, как super.onRestoreInstanceState завершит выполнение. - person Jason Robinson; 18.05.2012
comment
Кроме того, вы также можете переместить строку star.setOnCheckedChangeListener... в метод onResume, поскольку он вызывается после onRestoreInstanceState. В этом случае вам не нужно реализовывать onRestoreInstanceState. Я отредактирую свой ответ, чтобы показать эту опцию. - person Jason Robinson; 18.05.2012
comment
Что ж, это работает, как я сказал, если я устанавливаю if(mRestoringInstanceState), но не работает, если я устанавливаю if(!mRestoringInstanceState) - person eskalera; 18.05.2012
comment
@JasonRobinson: Разве ваше onResume решение не требует, чтобы слушатель был установлен на null в onPause? - person Squonk; 18.05.2012
comment
@MisterSquonk Нет, я не верю, что слушатели восстанавливаются через onRestoreInstanceState. - person Jason Robinson; 18.05.2012
comment
@eskalera Я только что понял, что вы делаете это в Adapter, а не в Activity. Делает мое решение бесполезным для вас. Позвольте предложить вам другое решение. - person Jason Robinson; 18.05.2012
comment
@eskalera Извините, я бросаю вам разные ответы, но проверьте мою вторую правку. - person Jason Robinson; 18.05.2012
comment
@ Джейсон Робинсон, спасибо, не волнуйся. Я просто понял, что ваше второе решение не может быть достигнуто, поскольку CheckBox еще не инициализирован. - person eskalera; 18.05.2012
comment
@JasonRobinson, сейчас работает как шарм! Я буду останавливаться на этом некоторое время, потому что еще не совсем понял. Спасибо большое. - person eskalera; 18.05.2012
comment
@eskalera Причина, по которой это работает, заключается в том, что, поскольку вы повторно используете представления в getView, star уже имеет прикрепленный к нему слушатель с момента последней передачи этого представления через getView. Поэтому, когда вы отметили star, он запускает последний назначенный ему слушатель. Вам решать, не инициализировать это перед проверкой. - person Jason Robinson; 18.05.2012

Его можно вызвать onRestoreInstanceState внутри вашего фрагмента

Вы можете отключить это с помощью

android:saveEnabled="false"

в определении макета флажка

person jmhostalet    schedule 10.06.2015
comment
Это лучшее решение действительно досадной проблемы. Если неожиданно вызывается onCheckedChanged (), попробуйте это. - person Whome; 06.10.2017

Я столкнулся с этой проблемой, используя собственный адаптер.

Я обнаружил, что проверяет, решает ли проблема кнопка isShown:

OnCheckedChangeListener ccl = new OnCheckedChangeListener()
{
    @Override
    public void onCheckedChanged(CompoundButton buttonView,
            boolean isChecked) {

        if(buttonView.isShown())
        {

        }
    }
};
person smetanma    schedule 20.03.2014
comment
Я думаю, что это прекрасное решение, поскольку система, вызывающая OnCheckedChangedListener, когда сама восстанавливает состояние, явно не то, чего хотят 99% разработчиков. Стоит отметить, что ViewCompat.isLaidOut (buttonView) также работает для этой цели и не привязан строго к видимости. - person Stephen Kidson; 30.06.2016