안드로이드 프래그먼트 전환시 RadioButton이 기존값으로 돌아가는 현상

안녕하세요. 개발자 드리머즈입니다.


RadioButton 사용 중에 원하는 대로 동작하지 않는 문제를 발견했습니다.


문제 현상

프래그먼트A와 프래그먼트B가 있고 두 프래그먼트 모두 RadioButton을 2개 가지고 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<RadioGroup
    android:layout_width="0dp"
    android:layout_height="40dp"
    android:layout_weight="3"
    android:layout_margin="10dp"
    android:orientation="horizontal"
    >
    <RadioButton
        android:id="@+id/rb1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="@string/text1"
        android:checked="true"
        />
 
    <RadioButton
        android:id="@+id/rb2"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="@string/text2"
        />
</RadioGroup>
cs


프래그먼트A에서 프래그먼트B를 실행시키며 프래그먼트B가 동작을 완료하면 프래그먼트B는 사라지고 다시 프래그먼트A가 샐힝됩니다. 이 때 프래그먼트B에서 선택되어져있던 RadioButton을 프래그먼트A에서도 선택하기 위해 프래그먼트B가 종료될 때 아래와 같은 코드를 실행시켜 프래그먼트A의 변수에 접근합니다.

1
 ((FragmentA)getFragmentManager().findFragmentByTag("FRAGMENT_A")).isFirstButtonChecked = isFirstButtonChecked;
cs


그리고 프래그먼트A가 다시 실행될 때 onCreateView()에서 아래의 코드가 실행되게 하여 프래그먼트B에 선택된 라디오버튼이 프래그먼트A에서도 유지되게끔 했습니다.

1
2
3
4
5
if(isFirstButtonChecked){
    rb1.setChecked(true);
}else{
    rb2.setChecked(true);
}
cs


하지만 실제 테스트를 해보면 프래그먼트B가 동작을 완료하여 사라지고 다시 프래그먼트A가 실행되면, 프래그먼트B에서 선택된 라디오 버튼이 프래그먼트A에서도 잠깐 선택되는 것처럼 보이다가 곧바로 원래 프래그먼트A에서 선택되어져있던 라디오 버튼이 선택됐습니다.

좀 더 자세히 예를들면 프래그먼트A에서 rb1이 선택되어져 있는 상태에서 프래그먼트B가 실행되어 프래그먼트B에서 rb2가 선택된 상태에서 동작을 완료하여 프래그먼트B가 사라지고 프래그먼트A가 다시 실행되면, 프래그먼트A의 rb2가 잠깐 선택되려는 모습을 보이다가 곧바로 rb1이 선택된다는 것입니다. 원하는 대로 동작하지 않았습니다.



원인

제가 작성한 코드에서 원치않게 프래그먼트A에서 선택된 라디오 버튼이 유지되게끔 하는 코드가 있을 거라고 생각했습니다. 그런데 아무리 찾아봐도 그런 코드가 없었습니다. 

두 라디오버튼에 setOnCheckedChangeListener을 등록해서 값이 변화하는 경우 부근을 디버깅 해봤습니다.

1
2
3
4
5
6
rb1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
        Log.d("Text""rb1 : onCheckedChanged() b = " + b);
    }
});
cs


디버깅을 했더니 안드로이드 네이티브 소스인 FragmentManager.java의 restoreViewState 함수가 불리자 프래그먼트A의 라디오버튼 선택이 기존값으로 돌아갔습니다.


*FragmentManager.java(안드로이드 native 소스)

1
2
3
if (f.mView != null) {
    f.restoreViewState(f.mSavedFragmentState);
}
cs


이름만 딱 들어봐도 프래그먼트A가 다시 시작될 때, 이전에 가지고 있던 값을 되찾기(restore)위해 실행되는 함수처럼 보입니다.

프래그먼트B가 동작을 완료하고 종료되면서 다시 프래그먼트A가 실행될 때, 프래그먼트B로 전달받은 값으로 라디오버튼을 선택했는데 그 이후로 restoreViewState

함수가 불려서 프래그먼트A가 기존에 가지고 있던 값을 되찾게 되는게 문제의 원인이었습니다.



해결 방법

Fragment의 Lifecycle을 고려해서 문제를 보면 restoreViewState()함수는 onStart() 이전에 반드시 동작이 완료되는 것으로 보입니다. 따라서 onStart()함수에서 라디오버튼을 갱신하는 작업을 하면 됩니다.


1
2
3
4
5
6
7
8
@Override
public void onStart() {
    if(isFirstButtonChecked){
        rb1.setChecked(true);
    }else{
        rb2.setChecked(true);
    }
}
cs


작성자

Posted by 드리머즈

관련 글

댓글 영역