Reputation: 4016
I'm working on an application where 90% of the activities inherit from a common activity and all these activities leak, meaning that if I go from A->B
and then B->A
(finish()
is called), B
's onDestroy()
gets called but it still leaks (checked with MAT).
The leaked activities are quite big (10MB~) so after going back and forth a few times the app crashes with OOM.
I've checked the heap dump and followed the path to GC roots for the leaking activities and they all look like this:
So I guess it's something in the common superclass that's leaking. I've already checked that all the BroadcastReceivers and listeners are unregistered when the activities get destroyed and there are no Handler
s used nor anonymous inner classes which may be causing the leak (it seems to me, at least).
What could be the cause of the leak? Any help would be really appreciated.
EDIT
I've found that there are two pieces of code that when commented out the activities are not leaking anymore:
ProgressDialog
.postDelayed
with an anonymous Runnable
.In the first case, the dialog's dismiss()
function is called before destruction, so I don't know why this could be the problem. In the second case, removeCallbacks is called for the Runnable
in onPause
, so theoretically it's properly cleaned, isnt' it?
Cheers.
Upvotes: 2
Views: 2656
Reputation: 4016
The problem turn out to be the anonymous Runnable
in postDelayed
. This Runnable
was called with the postDelayed()
function of the content view of the base activity, so it was something like this:
@Override
protected void onResume() {
...
mCallback = new Runnable() { ... };
getContentView().postDelayed(mCallback, mDelay);
}
The surprising part was that this callback was removed in onPause()
:
@Override
protected void onPause() {
...
getContentView().removeCallbacks(mCallback);
mCallback = null;
}
Why this didn't prevent the leak is still a mistery to me. At first I tried using getContentView().getHandler().removeCallbacksAndMessages(null)
and it fixed the leak, but then the app had things completely broken apart in seemingly unrelated places.
In the end what fixed the leak was creating a Handler
instance and calling postDelayed()
and removeCallbacks()
on this handler.
Upvotes: 2