removeObserver not working, observer keeps being executed

Viewed 1426

I have an activity that uploads pictures. Inside this activity I have following observer which is working perfectly:

pictureViewModel.customCreateResult.observeForever { result -> onResponsePostPicture(result!!)}

I need to use observeForever because the user sometimes navigates to other activities. This is working fine and is not the problem. When the user decides to leave this activity with the observer. So when finishing the activity I'm calling:

override fun onDestroy() {
        super.onDestroy()
        pictureViewModel.customCreateResult.removeObserver{ result -> onResponsePostPicture(result!!)}
}

When for example 2 out of 4 pictures are uploaded and then the user finishes the activity but decides to reopen the activity. I'm getting a respond of the last 2 pictures from the observer. So my removeObserver is not working. What am I doing wrong?

2 Answers

You are not adding and removing same observer each time you are creating anew one . You are passing a lambda which is a new observer every time . Below is an example .

private var observer:Observer<String> = Observer {
    onResponsePostPicture(it!!)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main2)
    pictureViewModel.customCreateResult.observeForever(observer)
}

override fun onDestroy() {
    super.onDestroy()
    pictureViewModel.customCreateResult.removeObserver(observer)
}

Alternatively you can use #removeObservers(this) Which will remove all the observers corresponds to Lifecycle Owner.

override fun onDestroy() {
    customCreateResult.removeObservers(this)
    super.onDestroy()
}

To add to what @ADM said, the issue is specifically that passing a lambda to observeForever/removeObserver creates a new Observer object that the system holds onto. Even if you pass the same lambda instance by holding it as a val, or anything like that, internally it's a new and completely different object.

So by registering an observer in this way, you cannot remove it with removeObserver and it will continue to receive events, and it can create large memory leaks if your lambda has references to things which lead back to something like an Activity.

The documentation doesn't warn you about this, and code completion for observeForever even suggests the lambda version, which is the way the rest of the Kotlin LiveData observer examples are written. It's a huge problem waiting to silently happen, and I wish they'd at least make people aware

Related