why this anonymous inner class instance for callback can't cause activity leak
I'm assuming that what you mean here is that it doesn't cause a memory leak, but it most certainly could, given that the scope in which you're instantiating the anonymous Callback
is an Activity
.
If you instantiate an inner class within an Android Activity
and then pass a reference to this instance to some other component, as long as this component is reachable, so will be the instance of the inner class. For instance, consider this:
class MemorySink {
static private List<Callback> callbacks = new ArrayList<>();
public static void doSomething(Callback callback){
callbacks.add(callback);
}
}
If you created instances of Callback
s from some activities and pass them to doSomething(callback)
, when one of the Activity
is destroyed the system will not use that instance anymore, it is expected that the garbage collector will release that instance. But, if MemorySink
here has a reference to a Callback
that has a reference to that Activity
, the instance of that Activity
will stay in memory even after being destroyed. Bam, memory leak.
So you say that your sample is not causing the memory leak, I will first suggest you to try out MemorySink
, create a simple Activity
"MainActivity" with 2 buttons and possibly some images to increase the memory footprint. In onCreate
set a listener on the first button this way:
findViewById(R.id.firstButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, MainActivity.class));
MemorySink.doSomething(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
finish();
}
});
You've just created a memory leak using Callback
. Every time you click on the button in MainActivity
that instance of MainActivity
will be destroyed and a new one will be created. But, the old instance of MainActivity
will be retained in memory. I invite you to click many times the button and then dump the memory (with Android Profiler in Android Studio), or use LeakCanary.
So, we've created a memory leak with Callback
, same class from OP. Now, let's add this method to MemorySink
:
public static void releaseAll() {
callbacks.clear();
}
And call it from another button on MainActivity
. If you press the first button many times (better if you have images in MainActivity
) you will see memory usages going up, even if you manually trigger garbage collection (Android Profile). Then you click this second button, all reference to Callback
are released, trigger garbage collection, and memory goes down. No more memory leak.
So the problem is not if Callback
can or cannot create a memory leak, it most certainly can. The problem is where are you passing that Callback
. In that case OkHttpClient
is not creating a memory leak, so you say, but it is not guaranteed at all that this will always happen. In that case you would need to be sure about the implementation of OkHttpClient
to say that it won't generate a memory leak.
My suggestion is to always assume that the memory leak can happen if you are passing a reference to an Activity
to some external class.