Android 实现RadioButton分两(多)行分布,并解决java.lang.StackOverflowError: stack size 8MB onCheckedChanged问题

一、实现RadioButton

1、效果图展示

效果如下如所示,所需要实现的功能是,实现两(多)行多个类目的单项选择。

2、XML布局实现

Android中提供了RadioButton供我们实现多个类目的单项选择,因为一般实现单项选择都需要多个类目中选择其中的一个,故而RadioButton一般需要搭配RadioGroup使用。然而RadioGroup是继承的LinearLayout,所以RadioButton排列方向只有水平或垂直中的一种,但是往往由于我们所添加的类目比较多,一行或一列不够地方陈列,所以有时候我们需要分成两(多)行显示,这个时候单单一个RadioGroup就不适用了,为了实现两(多)行显示,我们就需要用到两(多)组RadioGroup进行搭配。下面是步骤1中效果展示图的xml代码。

            <RadioGroup
                android:id="@+id/rgp_part_one"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:orientation="horizontal"
                android:gravity="center">

                <RadioButton
                    android:id="@+id/rbt_happy"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:checked="true"
                    android:textSize="18sp"
                    android:text="高兴" />

                <RadioButton
                    android:id="@+id/rbt_mad"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:checked="false"
                    android:textSize="18sp"
                    android:text="生气" />

                <RadioButton
                    android:id="@+id/rbt_sadness"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:checked="false"
                    android:textSize="18sp"
                    android:text="悲伤" />

            </RadioGroup>
            <RadioGroup
                android:id="@+id/rgp_part_two"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:orientation="horizontal"
                android:gravity="top|center_horizontal">
                <RadioButton
                    android:id="@+id/rbt_neutral"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:checked="false"
                    android:textSize="18sp"
                    android:text="厌恶" />

                <RadioButton
                    android:id="@+id/rbt_fear"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:checked="false"
                    android:textSize="18sp"
                    android:text="恐惧" />

                <RadioButton
                    android:id="@+id/rbt_amazed"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:checked="false"
                    android:textSize="18sp"
                    android:text="惊奇" />
            </RadioGroup>            

3、Java代码监听并执行事件

在步骤2中,我们用的是两(多)组的RadioGroup来实现两(多)行显示,分别表示为rgp_part_one和rgp_part_two,为了达到我们多类目的单项选择的目的,我们需要保证这两(多)组RadioGroup中有且只能有其中一组被选中,即这两(多)组RadioGroup的关系是互斥关系,其中一个被选中之后,剩余的都要清除掉被选中的状态。在MainActivity中,实现onCheckedChanged(RadioGroup group, int checkedId)方法,通过group.getId()来获取当前选中的RadioGroup的ID,并利用check(-1)的方法来清除其余RadioGroup的选中状态。最后通过checkedId来获取具体选中的RadioButton,并执行相对应的事件,代码如下所示。

 

public void onCheckedChanged(RadioGroup group, int checkedId) {
        
        switch (group.getId()){
            case R.id.rgp_part_one:
                rgp_part_two.check(-1);
                System.out.println("*********:rgp_part_two.clearCheck()");
                break;
            case R.id.rgp_part_two:
                rgp_part_one.check(-1);
                System.out.println("*********:rgp_part_one.clearCheck()");
                break;
        }
        switch (checkedId){
            case R.id.rbt_happy:
                emotion_selected=emotions[0];
                break;
            case R.id.rbt_mad:
                emotion_selected=emotions[1];
                break;
            case R.id.rbt_sadness:
                emotion_selected=emotions[2];
                break;
            case R.id.rbt_neutral:
                emotion_selected=emotions[3];
                break;
            case R.id.rbt_fear:
                emotion_selected=emotions[4];
                break;
            case R.id.rbt_amazed:
                emotion_selected=emotions[5];
                break;
        }
    }

二、StackOverflowError报错解决方法

1、StackOverflowError报错原因分析

通过一中的1、2、3,总共三个步骤,实现RadioButton的多类目单项选择,但是按照上述的代码走,到最后面执行的时候,发现了一个问题,即题目中说到的java.lang.StackOverflowError: stack size 8MB onCheckedChanged,刚开始是很蒙蔽的,不知道是什么情况,理论上说,这一套流程走下来应该是没有问题的才对,后来上网查询了相关的资料,应该是循环调用onCheckedChanged()方法所导致,为什么会这样子呢?原因就在check(-1)方法上,下面以rgp_part_two.check(-1)为例。

1)、我们选中rgp_part_one中标签为生气的RadioButton;

2)、这时候会触动onCheckedChanged()方法;

3)、并执行rgp_part_two.check(-1),该方法会遍历所有rgp_part_two组中的RadioButton,并清除该组中的RadioButton的选中状态;

4)、而在清除这些RadioButton的状态的时候,就又会触发onCheckedChanged(),就会从步骤4)回到步骤1),从而形成循环调用,从导致java.lang.StackOverflowError: stack size 8MB onCheckedChanged。

以上就是出现问题的原因。

2、解决方法

要解决这个问题,我们只需要在onCheckedChanged()中添加如下代码即可。

        View viewById = group.findViewById(checkedId);
        if (viewById==null||!viewById.isPressed()){
            return;
        }

这几行的代码起到的作用就是,每次触发onCheckedChanged()的时候,先判断是否有RadioButton被按下,如果没有,就返回。这就避免了我们在已经选择好了RadioButton,并且手已经离开屏幕的情况下,还反复触发rgp_part_two.check(-1)方法,导致循环迭代报错。

下面贴上修改过后的onCheckedChanged()方法代码。

public void onCheckedChanged(RadioGroup group, int checkedId) {
        View viewById = group.findViewById(checkedId);
        if (viewById==null||!viewById.isPressed()){
            return;
        }
        switch (group.getId()){
            case R.id.rgp_part_one:
                rgp_part_two.check(-1);
                System.out.println("*********:rgp_part_two.clearCheck()");
                break;
            case R.id.rgp_part_two:
                rgp_part_one.check(-1);
                System.out.println("*********:rgp_part_one.clearCheck()");
                break;
        }
        switch (checkedId){
            case R.id.rbt_happy:
                emotion_selected=emotions[0];
                break;
            case R.id.rbt_mad:
                emotion_selected=emotions[1];
                break;
            case R.id.rbt_sadness:
                emotion_selected=emotions[2];
                break;
            case R.id.rbt_neutral:
                emotion_selected=emotions[3];
                break;
            case R.id.rbt_fear:
                emotion_selected=emotions[4];
                break;
            case R.id.rbt_amazed:
                emotion_selected=emotions[5];
                break;
        }
    }

以上就是全部代码,可能写的不是很好,有错误的地方,欢迎各位同僚留言批评斧正,谢谢~

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值