Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- Kotlin
- Android
- 코틀린
- WebView
- 유튜브
- image
- ADB
- 깃헙
- coroutine
- 레트로핏
- build
- 안드로이드스튜디오
- 의존성주입
- 웹뷰
- viewpager
- 코루틴
- 안드로이드 스튜디오
- Retrofit
- RecyclerView
- 에러
- 스튜디오
- dart
- error
- 안드로이드
- Github
- 안스
- GIT
- Gradle
- MVVM
- studio
Archives
- Today
- Total
코딩하는 일용직 노동자
SingleLiveEvent 로 LiveData 중복 이벤트 처리하기 본문
MVVM 으로 개발할때 ViewModel은 View를 몰라야 합니다.
(ViewModel을 만들고 사용하는 activity가 자신의 context를 넘겨주거나 하지 않습니다.)
때문에 ViewModel에서 View로 이벤트나 결과를 전달할 경우에는 View가 ViewModel을 observe 하다가 상태가 변하면 그에따른 처리를 하게 합니다.
// ViewModel
var resetList = MutableLiveData<Boolean>().apply {
value = false
}
...
/**
* Search 버튼 클릭 처리.
*/
fun onClickSearch() {
if (!TextUtils.isEmpty(etStr)) {
mPage = 1
resetList.value = true
searchImage(etStr, mPage)
}
}
// View
viewModel.resetList.observe(viewLifecycleOwner, Observer {
if (it) {
viewModel.resetList.value = false
mImageAdapter?.resetList()
}
})
onClickSearch() 가 호출되면 resetList의 상태를 바꿔서 View 쪽이 신호를 받게 했습니다.
여기서 문제가 생기게 되는데, 이벤트를 받아서 처리할때마다 viewModel.resetList.value = false 로 다시 상태를 초기화 해주는 번거로움이 있습니다.
실수로 초기화 처리를 하지 않는다면 onClickSearch() 가 호출되더라도 이벤트가 처리되지 않을 것입니다.
또한, false로 초기화를 한다면 observe로 신호가 다시 한번 올것이고 그것을 필터링 하기 위해 if문을 추가해야 했습니다.
LiveData를 이용할때 중복된 신호가 올 경우를 막기위해 MutableLiveData를 상속받아 만든 SingleLiveEvent 로 처리하는 방법이 있습니다.
원본 파일 링크 => SingleLiveEvent.java
setValue() 에서 새로운 이벤트를 받으면 mPending 이 true로 바뀌고 observe 가 호출된다. 이벤트가 처리되면 false 로 바뀝니다.
/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.util.Log
import androidx.annotation.MainThread
import androidx.annotation.Nullable
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean
/**
* A lifecycle-aware observable that sends only new updates after subscription, used for events like
* navigation and Snackbar messages.
*
*
* This avoids a common problem with events: on configuration change (like rotation) an update
* can be emitted if the observer is active. This LiveData only calls the observable if there's an
* explicit call to setValue() or call().
*
*
* Note that only one observer is going to be notified of changes.
*/
class SingleLiveEvent<T> : MutableLiveData<T?>() {
private val mPending = AtomicBoolean(false)
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T?>) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}
// Observe the internal MutableLiveData
super.observe(owner, Observer {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(it)
}
})
}
@MainThread
override fun setValue(@Nullable t: T?) {
mPending.set(true)
super.setValue(t)
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
fun call() {
value = null
}
companion object {
private const val TAG = "SingleLiveEvent"
}
}
'안드로이드' 카테고리의 다른 글
안드로이드10(Q) 고유식별자 변경에 관하여 (0) | 2020.05.29 |
---|---|
ViewModelFactory 에 대해 간략히 알아보자. (0) | 2020.05.26 |
All children of ConstraintLayout must have ids to use ConstraintSet 에러 (0) | 2020.05.22 |
코틀린 콜렉션 함수 정리 (0) | 2020.05.22 |
ViewPager 의 높이를 wrap_content로 표시하는 방법 (0) | 2020.05.13 |