文档章节

【Android】OnCheckedChangeListener is called twice

xesam
 xesam
发布于 2014/01/15 14:15
字数 782
阅读 717
收藏 1

RadioGroup.OnCheckedChangeListener is called twice


今天又碰到了,貌似还没有被修复,顺便贴出来。

原android Issue地址:RadioGroup.OnCheckedChangeListener is called twice when the selection is cleared

具体表现

RadioGroup中包含有若干个RadioButton,当在代码中调用RadioGroup.check(id)方法动态设置被选中的RadioButton的时候,RadioGroup.OnCheckedChangeListener(RadioGroup group, int checkedId)会被调用多次。

示例

假设当前选择的是RadioButtonA,调用RadioGroup.check(RadioButtonBid)之后,RadioGroup.OnCheckedChangeListener(RadioGroup group, int checkedId)的调用情况如下:

第一次:checkedId为RadioButtonAId

第二次:checkedId为RadioButtonBId

第三次:checkedId为RadioButtonBId

测试代码

public class MainActivity extends Activity implements CompoundButton.OnCheckedChangeListener,
RadioGroup.OnCheckedChangeListener{

	RadioGroup mRadioGroup;
	RadioButton radio_0;
	RadioButton radio_1;
	RadioButton radio_2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mRadioGroup = (RadioGroup) findViewById(R.id.group);
		radio_0 = (RadioButton) findViewById(R.id.radio_0);
		radio_1 = (RadioButton) findViewById(R.id.radio_1);
		radio_2 = (RadioButton) findViewById(R.id.radio_2);

		mRadioGroup.setOnCheckedChangeListener(this);
		radio_0.setOnCheckedChangeListener(this);
		radio_1.setOnCheckedChangeListener(this);
		radio_2.setOnCheckedChangeListener(this);
	}

	public void doTestClick(View view) {
		switch (view.getId()) {
		case R.id.check_radio_0:
			mRadioGroup.check(R.id.radio_0);
			break;
		case R.id.check_radio_1:
			mRadioGroup.check(R.id.radio_1);
			break;
		case R.id.check_radio_2:
			mRadioGroup.check(R.id.radio_2);
			break;

		default:
			break;
		}
	}

	@Override
	public void onCheckedChanged(RadioGroup group, int checkedId) {
		Log.i("mRadioGroup onCheckedChanged", "checkedId:" + checkedId);
	}
	
	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		switch (buttonView.getId()) {
		case R.id.radio_0:
			Log.i("radio_0 onCheckedChanged", "isChecked:" + isChecked);
			break;
		case R.id.radio_1:
			Log.i("radio_1 onCheckedChanged", "isChecked:" + isChecked);
			break;
		case R.id.radio_2:
			Log.i("radio_2 onCheckedChanged", "isChecked:" + isChecked);
			break;

		default:
			break;
		}
	}

}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <Button
            android:id="@+id/check_radio_0"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doTestClick"
            android:text="check_radio_0" />

        <Button
            android:id="@+id/check_radio_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doTestClick"
            android:text="check_radio_1" />

        <Button
            android:id="@+id/check_radio_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="doTestClick"
            android:text="check_radio_2" />
    </LinearLayout>

    <RadioGroup
        android:id="@+id/group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <RadioButton
            android:id="@+id/radio_0"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="0" />

        <RadioButton
            android:id="@+id/radio_1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="1" />

        <RadioButton
            android:id="@+id/radio_2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="2" />
    </RadioGroup>

</LinearLayout>

产生原因

RadioGroup check简化如下:

public void check(int newid) {
	setCheckedStateForView(mCheckedId, false); //这里取消原来选择的RadioButton
	setCheckedStateForView(newid, true);//设置当前选中的RadioButton为激活状态
	setCheckedId(newid);//触发OnCheckedChangeListener
}

RadioGroup setCheckedStateForView简化如下:

private void setCheckedStateForView(int viewId, boolean checked) {
	RadioButton childRadioButton = (RadioButton)findViewById(viewId);
	childRadioButton.setChecked(checked);
}

RadioGroup setCheckedId简化如下:

private void setCheckedId(int id) {
	mCheckedId = id;//保存当前选择的RadioButton
	mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
}


同时RadioGroup内部有一个check状态跟踪器,简化一下如下:

private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
	public void onCheckedChanged(CompoundButton childRadioButton, boolean isChecked) {
	    int childRadioButtonId = childRadioButton.getId();
	    setCheckedId(id);
	}
}

当每一个RadioButton被添加到RadioGroup的时候,就给每一个RadioButton设置一个checked状态监听

childRadioButton.mOnCheckedChangeWidgetListener = mCheckedStateTracker;

所以每当RadioButton的check状态发生变化,都会触发check状态跟踪器。

RadioButton的setChecked(boolean)简化如下:

public void setChecked(boolean checked) {
	mOnCheckedChangeListener.onCheckedChanged(this, mChecked); //触发RadioButton各自的监听
	mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);//触发check状态跟踪器
}

说明

所以结合开头的例子,调用RadioGroup.check(RadioButtonBid)之后发生的情况如下:

1.RadioGroup.setCheckedStateForView(RadioButtonAid, false);
    --> RaidoButton.mOnCheckedChangeWidgetListener.onCheckedChanged(RadioButtonA, false) 
        --> RadioGroup.setCheckedId(RadioButtonAId) 
            --> RadioGroup.mOnCheckedChangeListener.onCheckedChanged(RadioGroup, RadioButtonAId);

2.RadioGroup.setCheckedStateForView(RadioButtonBid, true);
    --> RaidoButton.mOnCheckedChangeWidgetListener.onCheckedChanged(RadioButtonB, true) 
        --> RadioGroup.setCheckedId(RadioButtonBId) 
            --> RadioGroup.mOnCheckedChangeListener.onCheckedChanged(RadioGroup, RadioButtonBId);

3.RadioGroup.setCheckedId(RadioButtonBId) 
    --> RadioGroup.mOnCheckedChangeListener.onCheckedChanged(RadioGroup, RadioButtonBId);


按照Android官方文档的API说明:

public abstract void onCheckedChanged (RadioGroup group, int checkedId)
Parameters
    group	the group in which the checked radio button has changed
checkedId	the unique identifier of the newly checked radio button


那个checkedId的参数在实现上是名不副实的。


© 著作权归作者所有

共有 人打赏支持
xesam
粉丝 30
博文 77
码字总数 44843
作品 0
武汉
程序员
私信 提问
求教一个关于android界面切换,控件监听失效的问题。

具体是这样的,我使用一个activity操作多个layout。使用setcontentview()命令调用layout能实现界面显示。 在首界面我使用了radioground控件,使用oncheckedchangelistener作为radiobutton...

MAX_T
2013/08/27
1K
2
一起学Android之ToggleButton和Switch

本文以一个简单的小例子,简述在Android开发中ToggleButton(开关按钮)和Switch(开关)的简单使用,仅供学习分享使用。 概述 ToggleButton是一个有两种状态(checked/unchecked)的按钮,经...

Alan.hsiang
01/13
0
0
多排radiobutton单选

3排radiobutton分别用3个radiogroup包含: 布局如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layoutwidth="matchparent" android:layouthei......

STaR_枫
2013/12/09
0
0
Android高手来帮我看下这段代码为什么运行错误

额。。老师刚讲了个东西。。。跟着做了,也没报错,可以运行的时候说,意外关闭了。。。求高手帮看下。 先发个布局文件 以下是主程序 package com.amaker.test; import android.app.Activity...

黄恩赐
2012/05/08
668
18
Android基础教程(七)之----单选项框RadioGroup的综合应用

大家好,我们今天这一节要介绍的是RadioGroup 的组事件.RadioGroup 可将各自不同的RadioButton ,设限于同一个Radio 按钮组,同一个RadioGroup 组里的按钮,只能做出单一选择(单选题). 首先,我们...

神勇小白鼠
2011/01/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

租房软件隐私保护如同虚设

近日,苏州市民赵先生向江苏新闻广播新闻热线025-84658888反映,他在“安居客”手机应用软件上浏览二手房信息,并且使用该软件自动生成的虚拟号码向当地一家中介公司进行咨询。可电话刚挂不久...

linux-tao
25分钟前
1
0
分布式项目(五)iot-pgsql

书接上回,在Mapping server中,我们已经把数据都整理好了,现在利用postgresql存储历史数据。 iot-pgsql 构建iot-pgsql模块,这里我们写数据库为了性能考虑不在使用mybatis,换成spring jd...

lelinked
今天
2
0
一文分析java基础面试题中易出错考点

前言 这篇文章主要针对的是笔试题中出现的通过查看代码执行结果选择正确答案题材。 正式进入题目内容: 1、(单选题)下面代码的输出结果是什么? public class Base { private Strin...

一看就喷亏的小猿
今天
1
0
cocoapods 用法

cocoapods install pod install 更新本地已经install的仓库 更新所有的仓库 pod update --verbose --no-repo-update 更新制定的仓库 pod update ** --verbose --no-repo-update...

HOrange
今天
3
0
linux下socket编程实现一个服务器连接多个客户端

使用socekt通信一般步骤 1)服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept()等待客户端连接。 2)客户端:socker()建立套接字,连接(connect)服务器,连接上后...

shzwork
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部