일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- designPattern
- 추상팩토리패턴
- builderPattern
- 디자인패턴
- F
- Kotlin
- r
- Singleton
- ㅓ
- 함수형프로그래밍
- Design Pattern
- PrototypePattern
- El
- ㅋㅁ
- 코틀린
- factory method
- Abstract Factory
- Functional Programming
- 싱글톤
- Observer Pattern
- a
- 옵저버 패턴
- 추상 팩토리
- 팩토리 메소드
- 프로토타입 패턴
- 빌터패턴
- 디자인패턴 #
- Today
- Total
오늘도 더 나은 코드를 작성하였습니까?
two-way DataBinding(양방향 데이터 바인딩) 본문
two-way DataBinding
일반적인 데이터 바인딩은 ViewModel에서 Observable 한 데이터의 변화에 있어 그것을 UI에 바로 적용하는 방식이지만
반대로 UI의 변화를 ViewModel의 데이터에 주입하는것.
속성 = " @={ }"
간단한 예제.
public class MainActivity extends AppCompatActivity {
ActivityMainBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
ViewModel viewModel = new ViewModel();
mBinding.setViewModel(viewModel);
mBinding.setActivity(this);
}
public void onClickDone(View view){
mBinding.getViewModel().text.set("초기화 된다");
}
}
public class ViewModel extends BaseObservable {
public final ObservableField<String> text = new ObservableField<>("");
}
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="viewModel"
type="com.professionalandroid.apps.twowaydatabinding.ViewModel" />
<variable
name="activity"
type="com.professionalandroid.apps.twowaydatabinding.MainActivity" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Done"
android:onClick="onClickDone"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint"
android:text="@={viewModel.text}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.text}"/>
</LinearLayout>
</layout>
사용자 정의 속성을 이용한 양방향 바인딩 (아직 잘 이해가 안 된다.)
데이터 바인딩 라이브러리는 양방향 바인딩이 주로 사용되는 양방향 바인딩 속성에 대한 구현체를 이미 제공하지만 사용자가 직접 정의한 속성(BindingAdapter)에 대해 양방향 바인딩을 사용하려면 @InverseBindingAdapter와 @InverseBindingMethod 애노테이션을 사용한다.
1. 초기 값을 설정하고 데이터가 변경될 때 업데이트하는 메서드에 @BindingAdapter를 사용하여 주석을 추가합니다.
@BindingAdapter("time")
public static void setTime(MyView view, Time newValue) {
// Important to break potential infinite loops.
if (view.time != newValue) {
view.time = newValue;
}
}
2. 뷰에서 값을 읽는 메서드에 @InverseBindingAdapter를 사용하여 주석을 추가합니다
@InverseBindingAdapter("time")
public static Time getTime(MyView view) {
return view.getTime();
}
@BindingAdapter - viewModel(Data)가 변경되었을 때 수행하고 싶은 로직을 작성할 수 있고
@InverseBindingAdapter - 레이아웃의 사용자 정의 속성 값이 변경되었을 때 viewModel에 레이아웃 변수에 변경사항을 전달하여 양방향 바인딩을 구현하게 할 수 있다.
속성의 변경 시기 또는 방식을 알기 위해 뷰에 리스너를 설정해야 된다. 리스너는 맞춤 뷰와 연결된 맞춤 리스너이거나 포커스 상실 또는 텍스트 변경과 같은 일반 이벤트일 수 있습니다. 다음과 같이 속성 변경과 관련된 리스너를 설정하는 메서드에 @BindingAdapter 주석을 추가합니다.
@BindingAdapter("app:timeAttrChanged")
public static void setListeners(
MyView view, final InverseBindingListener attrChange) {
// Set a listener for click, focus, touch, etc.
}
참고: 모든 양방향 결합에서는 합성 이벤트 속성이 생성됩니다.
이 속성은 기본 속성과 이름이 동일하지만 접미사 "AttrChanged"가 있습니다. 합성 이벤트 속성을 사용하면 라이브러리가 @BindingAdapter를 통해 주석이 추가된 메서드를 생성하여 이벤트 리스너를 적절한 View 인스턴스에 연결할 수 있습니다.
양방향 바인딩 컨버터 사용하기
레아 이웃에 선언된 변수가 뷰에 양방향 바인딩되고, 화면에 나타나기 전에 특정 포맷으로 변경 또는 추가사항이 있는 상황이라면 컨버터를 사용한다.
예를 들어 EditText에 날짜를 표현한다 해보자.
<EditText
android:id="@+id/birth_date"
android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>
viewmodel.brithDate의 타입이 long타입이고 이를 우리가 읽고 이해하기 쉬운 문자열 형식의 날짜로 변경해야 된다.
양방향 바인딩 표현식이 사용된다면 반대로 문자열 --> long타입의 값으로 변경도 필요하다. 데이터 바인딩 라이브러리는 이러한 처리를 도와주는 @InverseMethod 애노테이션을 제공한다.
public class Converter {
@InverseMethod("stringToDate")
public static String dateToString(EditText view, long oldValue,
long value) {
// Converts long to String.
}
public static long stringToDate(EditText view, String oldValue,
String value) {
// Converts String to long.
}
}
양방향 데이터 결합을 사용하는 무한 루프
양방향 데이터 결합을 사용할 때 무한 루프가 발생하지 않도록 주의해야 합니다.
사용자가 속성을 변경하면 @InverseBindingAdapter를 사용하여 주석이 추가된 메서드가 호출되고 값이 backing 속성에 할당됩니다.
그러면 결과적으로 @BindingAdapter를 사용하여 주석이 추가된 메서드가 호출되고, 이것이 @InverseBindingAdapter를 사용하여 주석이 추가된 메서드를 또 호출하는 식으로 이어집니다.
따라서 @BindingAdapter를 사용하여 주석이 추가된 메서드의 새 값과 이전 값을 비교함으로써 발생 가능한 무한 루프를 끊는 것이 중요합니다.
사용자 입력 --> UI 변경--> ViewModel Data 변경 --> UI 반영 --> ViewModel Data 변경...... 무한 루프.
'Android Jetpack Architecture > DataBinding' 카테고리의 다른 글
DataBinding Incldue ViewStub 사용하기. (0) | 2020.08.12 |
---|---|
Observable 데이터 객체로 작업하기 (0) | 2020.08.10 |
DataBinding Component 사용하기 (0) | 2020.08.07 |
DataBinding 자동객체 전환 (0) | 2020.08.07 |
DataBinding 이벤트 처리하기 (0) | 2020.08.07 |