LiveData와 DataBinding을 이용하여 동적으로 TextView의 Text를 변경하는 로직을 적용했습니다.
예를들면, “Hello World” 를 “Hello Charles”는 것과 같이 단순한 변경이였습니다.
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewModel" type="com.charlezz.MainViewModel"/> </data> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.text}"/> </layout>
class MainViewModel: ViewModel (){ val text = MutableLiveData<CharSequence>().apply{ text.value = "Hello World" } fun changeText(enabled:Boolean){ text.value = "Hello Charles" } }
실제 위의 코드는 동작하는데 아무이상이 없었습니다.
“Hello World”에서 “Hello World”로 텍스트의 일부 색상만 바꾸면 어떻게 될까요?
우선 텍스트의 색상을 변경하는 코드는 다음과 같습니다.
class MainViewModel: ViewModel (){ val text = MutableLiveData<CharSequence>().apply{ text.value = "Hello World" } fun changeText(enabled:Boolean){ val spannable = SpannableString("Hello World") spannable.setSpan(ForegroundColorSpan(Color.BLUE), 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) text.value = spnnable } }
SpannableString을 만드는 것이죠.
실행하면 결과는 어떨까요?
“Hello World”가 되길 기대했지만 아무런 변화가 생기지 않습니다.
DataBinding을 사용하게 되면 레이아웃에 대한 LayoutNameBindingImpl객체가 생성되고, 각 위젯에 맞는 기 정의된 BindingAdapter를 통해서 데이터와 뷰가 바인딩 됩니다. TextView의 경우 TextViewBindingAdapter가 참조됩니다.
public class TextViewBindingAdapter { ... @BindingAdapter("android:text") public static void setText(TextView view, CharSequence text) { final CharSequence oldText = view.getText(); if (text == oldText || (text == null && oldText.length() == 0)) { return; } if (text instanceof Spanned) { if (text.equals(oldText)) { return; // No change in the spans, so don't set anything. } } else if (!haveContentsChanged(text, oldText)) { return; // No content changes, so don't set anything. } view.setText(text); } ... }
실행시 text가 아직 초기화되지 않은채로 바인딩이 되는경우(null)와 동일한 텍스트가 반복적으로 바인딩되는 경우가 있기 때문에, 퍼포먼스 향상을 위해서 view.setText(text)가 호출되기 까지 몇개의 조건문을 통해 걸러주고 있는 모습입니다. 바로 이점 때문입니다. oldText(Hello World)와 새로 들어오는 text(Hello World)가 같기 때문에 setText(text)가 호출되지 않아 렌더링 되지 않았던 것이죠.
그래서 아래와 같이 저는 CustomBindingAdapter로 해결을 했습니다.
@BindingAdapter("textByForce") public static void setText(EditText view, CharSequence text){ if(TextUtils.isEmpty(text)){ return; } view.setText(text); }
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewModel" type="com.charlezz.MainViewModel"/> </data> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:textByForce="@{viewModel.text}"/> </layout>
0개의 댓글