얼마전, TextView#setText(CharSequence), EditText#setText(CharSequence)를 호출하여 사용 중 차이점 하나를 발견하였습니다. View 내부 상태를 복원할 때, TextView의 text 초기화되지만, EditText의 text는 유지된다는 점입니다.
어떠한 원인으로 이런 차이가 발생하는지 살펴보겠습니다.
setText(CharSequence)구현 차이가 있을까? 없습니다.EditText는setText()를 재정의하지 않기 때문에, 부모 클래스인TextView의setText()를 그대로 사용합니다.- 상태를 저장하고, 복원하는
onSaveInstanceState()와onRestoreInstanceState()구현 차이가 있을까? 없습니다. 위의 메소드도 재정의없이 부모 클래스 메소드를 그대로 사용합니다.
하지만 상태가 저장되고 있기 때문에, 상태를 처리하는 onSaveInstanceState()와 onRestoreInstanceState() 에서 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
EditTextit 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
EditTextit is always enabled, regardless of the value of the attribute.
EditText는 freezesText 속성과 상관없이 항상 true 이며, getFreezesText() 구현으로 확인할 수 있습니다.
@Override
public boolean getFreezesText() {
return true;
}결국, EditText의 getFreezesText()는 항상 true 를 반환하도록 재정의되었고, 이로 인해 TextView와는 다르게 text 상태가 보존될 수 있었던 것입니다. TextView 에서도 setFreezesText(Boolean) 또는 freezesText 속성을 true 로 설정한다면 text 상태를 보존할 수 있습니다.
