I have a Java class that holds listeners using weak references. When I pass Kotlin lambdas as listeners, the weak reference get()
method returns null. I suspect the objects are garbage-collected even though the caller still holds a reference to them. However, if I pass a regular Kotlin object instead of a lambda, this behavior doesn't occur.
Kotlin code:
companion object {
// This lambda IS being garbage collected after a while
val aLambda: (bundle: Bundle?, caller: Fragment?) -> Unit = { _, _ -> if (something()) processRequest() }
// This object IS NOT being garbage collected
val anObject = object: Notifications.Listener {
override fun onNotification(bundle: Bundle?, caller: Fragment?) {
if (something()) processRequest()
}
}
init {
// This Notifications class holds weak references to both the lambda & object the same way
Notifications.addListener(aLambda)
Notifications.addListener(anObject)
}
}
Java code:
public class Notifications {
private static ArrayList<WeakReference<Listener>> listenersArray = new ArrayList<>();
public static void addListener(@NonNull Listener listener) {
listenersArray.add(new WeakReference<>(listener));
}
public static void notify(@Nullable Bundle bundle, @Nullable Fragment caller) {
for (WeakReference<Listener> weakListener : listenersArray) {
Listener listener = weakListener.get();
if (listener != null) {
listener.onNotification(bundle, caller);
}
}
}
}
What gets garbage-collected is not the lambda object itself, but the temporary Notifications.Listener
object that the compiler automatically generates when you call this function:
Notifications.addListener(aLambda)
Since Notifications.addListener
takes a parameter of type Notifications.Listener
, such an object needs to be created from the given lambda (because Notifications.addListener
is a functional interface). Since you're only holding this Notifications.Listener
object via a WeakReference
, it gets garbage-collected. The lambda itself is never garbage-collected since the property aLambda
continues to hold a reference to it.
If you define aLambda
as follows instead, then its type will be what is required by addListener
and it will not be garbage-collected since the Listener
object will now have a strong reference held by aLambda
.
val aLambda = Notifications.Listener { _, _ -> if (something()) processRequest() }