Reputation: 33126
We want to observe the changes in the size of a view and we create an extension like this:
fun View.layoutSizeObservable(): io.reactivex.Observable<Size> {
return io.reactivex.Observable.create<Size> { emitter ->
viewTreeObserver.addOnGlobalLayoutListener {
Log.d("MainFragment", "ViewTreeObserver Listener called back.")
if (measuredWidth > 0 && measuredHeight > 0) {
emitter.onNext(Size(measuredWidth, measuredHeight))
}
}
}
}
And then we use it like this, which works fine functionally:
sizeChangedDisposable = titleTextView.layoutSizeObservable().subscribe { size: Size ->
Log.d("MainFragment", "Size changed subscribe on $size")
}
However, one thing that is not exactly what we want is that the Listener
is added via addOnGlobalLayoutListener
, but never removed.
We can call sizeChangedDisposable.dispose()
which will properly stop the subscription:
D/MainFragment: Size changed subscribe on $size
But this will continue to get called:
D/MainFragment: ViewTreeObserver Listener called back.
How and where do we remove the layout listener call back?
Upvotes: 2
Views: 1637
Reputation: 4194
You need to remove the listener when the Disposable
is disposed. To be able to do that, set a Cancellable
action to the emitter removing the listener.
Example
fun View.layoutSizeObservable(): io.reactivex.Observable<Size> {
return io.reactivex.Observable.create<Size> { emitter ->
val listener = ViewTreeObserver.OnGlobalLayoutListener {
Log.d("MainFragment", "ViewTreeObserver Listener called back.")
if (measuredWidth > 0 && measuredHeight > 0) {
emitter.onNext(Size(measuredWidth, measuredHeight))
}
}
viewTreeObserver.addOnGlobalLayoutListener(listener)
emitter.setCancellable {
Log.d("MainFragment", "ViewTreeObserver Listener removed.")
viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
}
}
BTW, RxBinding library already has an Observable
for global layout listener
Upvotes: 5