# TextView의 상태 저장

매일 수정하는 GNOSS LV5·2022년 6월 20일
1

AndroidStudio

목록 보기
74/83

발단

A화면에서 setText를 이용하여 EditText2개와 TextView3개의 필드에 각각의 값들을 입력하고
B화면으로 넘어간 후에 다시 A화면으로 돌아오는 경우가 있었습니다.

이때 EditText에 입력된 값들은 그대로 남아있었지만, TextView에 입력한 값들은 전부 사라지는 경우가 생겼습니다.

디버깅

각각의 View에 입력하는 값이 전부 달랐기 때문에 2가지 가정을 세웠습니다.

  1. TextView에 해당하는 데이터들이 들어오지 않는다.
  2. onViewCreated에서 EditText에 관련된 값들만 setText를 다시 해준다.

두가지에 대한 테스트를 진행한 결과 모든 데이터가 정상적으로 들어왔고 setText문제도 없었다.

값들의 차이점을 찾아보니 EditText와 TextView의 차이점이 있었다.

결론

View의 내부 상태를 복원할 때, TextView의 text가 초기화되지만 EditText의 text는 유지된다.

그렇다면 두개의 차이점이 무엇일까??


디버깅

  1. setText의 구현 차이??

    1. 결론은 차이가 없다.
      EditText는 setText()를 재정의하지 않으며 TextView의 setText()를 그대로 사용한다.
  2. 상태를 저장하고 복원하는 onSaveInstanceState()에 View속성에 따라 다르게 처리하는 부분이 있는가?

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());

        // XXX restore buffer type too, as well as lots of other stuff
        if (ss.text != null) {
            setText(ss.text);
        }

      .....

위의 구현을 보면, SavedState 의 text 를 가져와서 setText()를 호출하고 있다.
그렇다면 TextView의 text도 복원되어야하는 것은 아닐까?
하지만 TextView 의 text 복원되지 않기 때문에 text==null이며 onSaveInstanceState()에서 상태를 저장하지 않는다는 의미이다.

TextView 에서 상태를 저장하지 않는 원인을 찾아보기 위해, onSaveInstanceState() 구현을 살펴보자.

public Parcelable onSaveInstanceState() {    Parcelable superState = super.onSaveInstanceState();    // Save state if we are forced to
    **final boolean freezesText = getFreezesText();**
    boolean hasSelection = false;
    int start = -1;
    int end = -1;

    if (mText != null) {
        start = getSelectionStart();
        end = getSelectionEnd();
        if (start >= 0 || end >= 0) {
           // Or save state if there is a selection
           hasSelection = true;
        }
    }

    if (**freezesText** || hasSelection) {
        SavedState ss = new SavedState(superState);
				if (**freezesText**) {
            if (mText instanceof Spanned) {
                final Spannable sp = new SpannableStringBuilder(mText);

                if (mEditor != null) {
                    removeMisspelledSpans(sp);
                    sp.removeSpan(mEditor.mSuggestionRangeSpan);
                }                ss.text = sp;            
								} else {
                ss.text = mText.toString();
            }
        }
.....

SavedState의 text 는 getFreezesText() == true인 경우에 할당하고 있다.

API 문서에서 설명하고 있는 getFreezesText() 는 아래와 같다.

Return whether this text view is including its entire text contents in frozen icicles. For EditText it always returns true.

또한 freezesText 속성의 설명은 아래와 같다.

If set, the text view will include its current complete text inside of its frozen icicle in addition to meta-data such as the current cursor position. By default this is disabled; it can be useful when the contents of a text view is not stored in a persistent place such as a content provider. For EditText it is always enabled, regardless of the value of the attribute.

최종 결론

EditText의 greezesText속성은 항상 true 이다.

 @Override
 public boolean getFreezesText() {
     return true;
 }

결국, EditText의 getFreezesText()는 항상 true 를 반환하도록 재정의되어있다.
이로 인해 TextView와는 다르게 text 상태가 보존될 수 있었던 것이다. 
TextView 에서도 setFreezesText(Boolean) 또는 freezesText 속성을 true 로 설정한다면
text 상태를 보존할 수 있.다다

profile
러닝커브를 따라서 등반중입니다.

0개의 댓글