When writing instead of Java's anonymous inner class with a lambda expression, I assumed that it would be a separate instance, and this is a memo that became a problem in managing each instance.
In order to realize that the data source managed by one LiveData can be provided as another LiveData by using LiveData of Android Architecture Components, the following implementation passes an empty Observer to LiveData.observer. I was addicted to it.
Sample code
kotlin
//Counter LiveData that increments every second only while being observed
class Counter : LiveData<Int>() {
private var timer: Timer? = null
//LiveData that delivers only even numbers while relying on outer class counters
var oddCounter: MutableLiveData<Int> = object : MutableLiveData<Int>() {
override fun observe(owner: LifecycleOwner, observer: Observer<Int>) {
super.observe(owner, observer)
//Because there is a counter in the outer class
//By observing that too, make it active and start the counter.
[email protected](owner, Observer<Int> { })
}
}
override fun onActive() {
val task = object : TimerTask() {
override fun run() {
var nextCount = (value ?: 0) + 1
postValue(nextCount)
if (nextCount % 2 != 0) {
oddCounter.postValue(nextCount)
}
}
}
timer = Timer()
timer?.scheduleAtFixedRate(task, 0, 1000)
}
override fun onInactive() {
timer?.cancel()
}
}
class MainKotlinActivity : AppCompatActivity() {
private val counter = Counter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Code that activities and processes observe in a sample implementation that is observed by multiple owners
counter.oddCounter.observe(this, Observer<Int> { value ->
value?.let { println("activity got $it") }
})
counter.oddCounter.observe(ProcessLifecycleOwner.get(), Observer<Int> { value ->
value?.let { println("process got $it") }
})
}
}
When I do this, the code [email protected] (owner, Observer <Int> {})
is called twice for different ʻowner instances, but the second time it is
java.lang.IllegalArgumentException. I get the exception: Cannot add the same observer with different lifecycles`.
The cause is as follows.
--ʻObserver returns the same instance (within the same class) no matter how many times it is run --[Specifications] of
LiveData.observe` (https://developer.android.com/reference/androidx/lifecycle/LiveData.html#observe (androidx.lifecycle.LifecycleOwner,% 2520androidx.lifecycle.Observer% 3C?% 2520super" % 2520T% 3E)), one observer cannot be used by different owners
Probably, ʻObserver is diverting one instance because the closure does not depend on the scope of the caller and is fixed. In fact, unless ʻObserver <Int> {}
is ʻObserver , that is, the implementation depends on ʻowner
, which changes with each call. Returned an instance.
In the first place, I think that the bytecode is completely different from the anonymous inner class and the lambda expression, so http://www.ne.jp/asahi/hishidama/home/tech/java/lambda.html#h_invokedynamic Read this Hum Hum.
This time, I wrote ʻObserver
The most orthodox way: Java's anonymous innerclass.
java
Observer<Integer> nullObserver = new Observer<Integer>() {
@Override
public void onChanged(@Nullable Integer integer) {
}
};
observe(owner, nullObserver);
But this is suggested to Android Studio as "can be replaced with lambda", which translates to code that uses a lambda expression as follows:
java
Observer<Integer> nullObserver = value -> {};
observe(owner, nullObserver);
Same with Kotlin.
kotlin
val nullObserver = object : Observer<Int> {
override fun onChanged(t: Int?) {
}
}
observe(owner, nullObserver);
kotlin
val nullObserver = Observer<Int> { }
observe(owner, nullObserver);
I realized again that I should be aware of the differences between them and use them properly.
If you simply leave the original anonymous inner class or object expression, another person may make the same change again according to the IDE's suggestion, so instantiate a dedicated class as follows: I made it.
kotlin
private class NullObserver<T> : Observer<T> {
override fun onChanged(t: T?) {
}
}
observe(owner, NullObserver<Int>())
While compiling the qiita article now, I wondered if it was okay to supplement something with source code comments.
end.
By the way, with the sample code written here, if you use Transformations, you will not have to do such a complicated sky observe. However, the actual code may be a little more complicated.
Recommended Posts