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

本文深入探讨了在Android中使用RadioGroup的check(id)方法时,为何会导致onCheckedChanged监听器被触发多次的问题。通过分析RadioGroup的源码,包括setCheckedId(id)、setCheckedStateForView()以及RadioButton的setChecked()方法,揭示了这一现象的原因。
AI助手已提取文章相关产品:

原文《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);
        }
    }

整理一下。
RadioGroup .check(id)
    1.1  RadioGroup .setCheckedStateForView(mCheckedId, false);
    1.2  RadioGroup .setCheckedStateForView(id, true);
    1.3  RadioGroup .setCheckedId(id);
RadioGroup 在setCheckedId中调用 RadioGroup onCheckedChanged
RadioGroup .setCheckedStateForView调用 RadioButton .setChecked(boolean checked)
RadioButton .setChecked调用 RadioButton .mOnCheckedChangeListener
RadioButton .mOnCheckedChangeListener是 RadioGroup .mChildOnCheckedChangeListener 
RadioGroup .mChildOnCheckedChangeListener是new  RadioGroup .CheckedStateTracker();
RadioGroup .CheckedStateTracker 调用 RadioGroup .setCheckedId

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值