平方X 发表于 2016-7-17 09:37:28

RadioGroup调用check(id)方法时,onCheckedChanged被执行多次

参考:
《RadioGroup调用check(id)方法时,onCheckedChanged方法被执行多次解决办法》
《RadioGroup calls onCheckChanged() three times》
遇到这个问题的时候,我是看了源码的,但是没认真看,以为出问题了。
参考了上面两篇之后,确定是源码的原因,于是又认真看了源码
解决方案是直接调用RadioButton.setChecked(),可以findViewById或者getChildAt
原因是
1.首先看RadioGroup.check(id)
public void check(@IdRes int id) {
      // don't even bother
      if (id != -1 && (id == mCheckedId)) {
            return;
      }

      if (mCheckedId != -1) {
            //1.1
            setCheckedStateForView(mCheckedId, false);
      }

      if (id != -1) {
            //1.2
            setCheckedStateForView(id, true);
      }
      //1.3
      setCheckedId(id);
    }
2.注意上面的setCheckedId(id)方法,在这个方法中调用的onCheckedChanged
private void setCheckedId(@IdRes int id) {
      mCheckedId = id;
      if (mOnCheckedChangeListener != null) {
            mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
      }
    }
3.也就是说被执行2次(如果还没有选中项)或3次(已经有选中项了),都是在setCheckedId(id)中执行的。
在check(id)中调用setCheckedStateForView()执行了1或2次,最后直接执行了1次。
接下来看setCheckedStateForView()中是怎么调用的:
private void setCheckedStateForView(int viewId, boolean checked) {
      View checkedView = findViewById(viewId);
      if (checkedView != null && checkedView instanceof RadioButton) {
            ((RadioButton) checkedView).setChecked(checked);
      }
    }
4.跳转到了RadioButton的setChecked()方法
public void setChecked(boolean checked) {
      if (mChecked != checked) {
            mChecked = checked;
            ...
            if (mOnCheckedChangeListener != null) {
                mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
            }
            ...
      }
    }
5.在RadioGroup中的申明
    private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
6.在RadioGroup中的初始化
    mChildOnCheckedChangeListener = new CheckedStateTracker();
7.CheckedStateTracker
    private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            // prevents from infinite recursion
            if (mProtectFromCheckedChange) {
                return;
            }

            mProtectFromCheckedChange = true;
            if (mCheckedId != -1) {
                setCheckedStateForView(mCheckedId, false);
            }
            mProtectFromCheckedChange = false;

            int id = buttonView.getId();
            setCheckedId(id);
      }
    }
整理一下。
1 RadioGroup.check(id)
    1.1 RadioGroup.setCheckedStateForView(mCheckedId, false);
    1.2 RadioGroup.setCheckedStateForView(id, true);
    1.3 RadioGroup.setCheckedId(id);
2 RadioGroup在setCheckedId中调用RadioGrouponCheckedChanged
3 RadioGroup.setCheckedStateForView调用RadioButton.setChecked(boolean checked)
4 RadioButton.setChecked调用RadioButton.mOnCheckedChangeListener
5 RadioButton.mOnCheckedChangeListener是RadioGroup.mChildOnCheckedChangeListener
6 RadioGroup.mChildOnCheckedChangeListener是new RadioGroup.CheckedStateTracker();
7 RadioGroup.CheckedStateTracker 调用RadioGroup.setCheckedId
页: [1]
查看完整版本: RadioGroup调用check(id)方法时,onCheckedChanged被执行多次