In a RecyclerView adapter, I have ```init { so...
# android
m
In a RecyclerView adapter, I have
Copy code
init {
    someInstance.someVal = { someHelper.someFun(it) }
}
and LeakCanary hinted that this was causing a leak, so (as a complete stab in the dark) I switched to using a method reference and the leak seemed to go away. Can anyone explain why such a seemingly minor change could fix a leak, please?
Copy code
init {
    someInstance.someVal = someHelper::someFun
}
☝🏻 1
m
z
I believe this is because in the first case, because you're referencing
someHelper
from your lambda, presuming
someHelper
is a property on your class, that lambda code is actually doing
this.someHelper.someFun
. Ie your lambda "captures" a reference to
this
, so it can call
someHelper
on it later. This is probably where the leak comes from. You can verify this is what's happening by looking at the Kotlin bytecode generated for this (in intellij, "Show kotlin bytecode"). In the second case, the code is getting the
someHelper
reference eagerly and storing it in the bound method reference. It's effectively doing:
Copy code
val someHelperCapture = this.someHelper
{ someHelperCapture.someFun(it) }
Because this lambda no longer references
this
, the compiler doesn't bother storing a reference to it in the lambda object (ie. it's not captured), so you're no longer leaking it.
👍 1
💯 1
m
Thanks! that explains it. Indeed
someHelper
is a private val (declared in constructor). When I change to using a method reference, I see that it can be a
private val
-less constructor argument indicating (as you say) that it is being referenced directly as opposed to via
this
before. Not sure why the compiler doesn’t reference it directly anyway though (since it’s neither a var nor has a custom getter).
z
Yea, seems like it could do that automatically. I'm guessing it might be for consistency? Idk