Ответ 1
почему этот анонимный экземпляр внутреннего класса для обратного вызова не может вызвать утечку активности
Я предполагаю, что вы имеете в виду, что это не вызывает утечку памяти, но это, безусловно, могло бы, учитывая, что область, в которой вы создаете анонимный Callback
представляет собой Activity
.
Если экземпляр внутреннего класса внутри Android Activity
, а затем передать ссылку на этот экземпляр в какой - то другой компонент, если этот компонент доступен, так будет экземпляром внутреннего класса. Например, рассмотрим следующее:
class MemorySink {
static private List<Callback> callbacks = new ArrayList<>();
public static void doSomething(Callback callback){
callbacks.add(callback);
}
}
Если вы создали экземпляры Callback
из некоторых действий и doSomething(callback)
их doSomething(callback)
, когда одно из Activity
уничтожено, система больше не будет использовать этот экземпляр, ожидается, что сборщик мусора выпустит этот экземпляр. Но, если MemorySink
здесь есть ссылка на Callback
, который имеет ссылку на эту Activity
, экземпляр этой Activity
будет оставаться в памяти даже после того, как разрушаются. Bam, утечка памяти.
Таким образом, вы говорите, что ваш образец не вызывает утечку памяти, я сначала предлагаю вам попробовать MemorySink
, создать простую Activity
"MainActivity" с 2 кнопками и, возможно, некоторыми изображениями, чтобы увеличить объем памяти. В onCreate
задайте слушателя на первой кнопке следующим образом:
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();
}
});
Вы только что создали утечку памяти, используя Callback
. Каждый раз, когда вы нажимаете кнопку в MainActivity
, экземпляр MainActivity
будет уничтожен и будет создан новый. Но старый экземпляр MainActivity
будет сохранен в памяти. Я приглашаю вас многократно нажимать кнопку, а затем выгружать память (с Android Profiler в Android Studio) или использовать LeakCanary.
Итак, мы создали утечку памяти с помощью Callback
, тот же класс из OP. Теперь добавим этот метод в MemorySink
:
public static void releaseAll() {
callbacks.clear();
}
И назовите его с другой кнопки MainActivity
. Если вы нажмете первую кнопку много раз (лучше, если у вас есть изображения в MainActivity
), вы увидите, что MainActivity
памяти MainActivity
, даже если вы вручную запускаете сбор мусора (профиль Android). Затем вы нажимаете эту вторую кнопку, освобождаются все ссылки на Callback
, запускают сборку мусора и память опускается. Больше утечки памяти.
Поэтому проблема заключается не в том, что Callback
может или не может создать утечку памяти, это, безусловно, может. Проблема в том, где вы передаете этот Callback
. В этом случае OkHttpClient
не создает утечку памяти, поэтому вы говорите, но это не гарантирует, что это всегда произойдет. В этом случае вам нужно быть уверенным в реализации OkHttpClient
чтобы сказать, что он не будет генерировать утечку памяти.
Мое предложение состоит в том, чтобы всегда предполагать, что утечка памяти может произойти, если вы передаете ссылку на Activity
на какой-либо внешний класс.