상품등록시 이런 형태의 UI 에서 Rx Subject + LiveData 처리 하는 방법
-> 해당 아이템이 선택됐을때를 Subject<List<T>> 으로 묶는게 최종 목적
private val _onDealTypeChanged: Subject<List<UserProduct.DealType>>
1. (기존) 체크박스에 CheckedChangeListener를 연결하여 뷰모델에서 combineLatest 로 묶는 방법
<CheckBox
android:id="@+id/cb_direct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_stroke_verylightpink_dustyorange_checked_selector"
android:text="직거래"
android:checked="@{output.isDirect}"
android:textColor="@color/selector_lightperiwinkle_dustyorange"
bind:checkedChanges="@{input.onDirectChanged}" />
@BindingAdapter("checkedChanges")
fun CheckBox.bindCheckedChanges(subject: Subject<Boolean>) {
this.setOnCheckedChangeListener { _, isChecked ->
subject.onNext(isChecked)
}
}
Observable.combineLatest(
_onDirectChanged,
_onDeliveryChanged,
_onPostChanged,
{ direct: Boolean, delivery: Boolean, post: Boolean ->
Triple(direct, delivery, post)
}
).map { (direct, delivery, post) ->
val dealTypeList = mutableListOf<UserProduct.DealType>()
if (direct) dealTypeList.add(UserProduct.DealType.DIRECT)
if (delivery) dealTypeList.add(UserProduct.DealType.DELIVERY)
if (post) dealTypeList.add(UserProduct.DealType.POST)
}.subscribe(_onDealTypeChanged::onNext)
.addDisposable()
_onDirectChanged.bind(_isDirect)
...
-> 문제점 : 상품을 등록할때는 문제가 없다. 하지만 상품을 수정할때 기존 선택된 항목들을 보여준다고 했을때
_onDealTypeChanged
.map{ dealType->
if(dealType.contains(UserProduct.DealType.DIRECT)) _onDirectChanged.onNext(true)
if(dealType.contains(UserProduct.DealType.DELIVERY)) _onDeliveryChanged.onNext(true)
if(dealType.contains(UserProduct.DealType.POST)) _onPostChanged.onNext(true)
}.subscribe()
.addDisposable()
dealTypeChanged 변수에 기존에 선택했던 항목들의 리스트를 받아와서
각각 항목이 포함되어 있으면 각 CheckedChangeListener에 걸려있는 Subject를 true로 방출
-> 이렇게 되면 다시 위의 combineLatest 가 동작하면서 무한루프가 돌게됨
2. 리팩토링 : CheckBox에 onClickListener를 연결,
<CheckBox
android:id="@+id/cb_direct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_stroke_verylightpink_dustyorange_checked_selector"
android:text="직거래"
android:checked="@{output.isDirect}"
android:onClick="@{()->input.onDealTypeDirectClick()}"
android:textColor="@color/selector_lightperiwinkle_dustyorange"/>
private val _onDealTypeClick: Subject<UserProduct.DealType> = PublishSubject.create()
override fun onDealTypeDirectClick() = _onDealTypeClick.onNext(UserProduct.DealType.DIRECT)
override fun onDealTypeDeliveryClick() = _onDealTypeClick.onNext(UserProduct.DealType.DELIERY)
override fun onDealTypePostClick() = _onDealTypeClick.onNext(UserProduct.DealType.POST)
_onDealTypeChanged
.takePairWhen(_onDealTypeClick)
.map { (dealType, type) ->
dealType.edit {
if (contains(type)) {
remove(type)
} else {
add(type)
}
}
}
.subscribe(_onDealTypeChanged::onNext)
.addDisposable()
_onDealTypeChanged
.map { it.contains(UserProduct.DealType.DIRECT) }
.bind(_isDirect)
...
(takePairWhen = withLatestFrom 연산자, Click 했을때 동작 )
-> 이렇게 연결하면 기존 선택된 값을 가져올때도 정상적으로 동작한다
결론 : CheckBox의 CheckedChangeListener는 Subject와 연결해서 사용하면 이런 이슈들이 자주 생기는것 같다.
OnClickListener 으로 연결하는게 번거롭긴 하지만 유지보수면에선 유리한 것 같다.
'Android' 카테고리의 다른 글
댓글 찾기 (0) | 2021.08.19 |
---|---|
데이터 조작 : flatMap 활용하기 (0) | 2021.08.09 |
Grid 격자 테두리 그리기(onDraw in RecyclerView.ItemDecoration) (0) | 2021.07.04 |
TroubleShooting With AppbarLayout expand (0) | 2021.06.06 |
상품리스트 - 좋아요 - 툴팁 - 트러블 슈팅 (0) | 2021.06.05 |