Как избежать утечек памяти из-за пользовательского класса статического обработчика? - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть определенные утечки памяти, происходящие в моем пользовательском классе обработчика, но я не уверен, как это исправить.проверил пару примеров в Интернете, но для моего кода ничего не характерно, поэтому не знаю, как это сделать:

private val startupCallback = object: RetryCallback(NUMBER, DELAY) {
        override fun onRetry(retryCount: Int) {

            mySdkApi.applicationStartup(this)
        }

        override fun onCompleted(): Boolean {
            updateStatus(Callback.Status.StartUpSDK)

            return true
        }

        override fun onFailed(e: MyException?) {
            updateStatus(Callback.Status.StartUpSDK, "", e)
        }
    }

Студия Android продолжает подсказывать: «Этот класс обработчика должен быть статическим, иначе могут возникнуть утечки». Любые идеикак это сделать?

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Жалобы Android Studio довольно разумные.Проблема в том, что анонимные классы захватывают ссылку на родительский класс, в котором они были созданы.

В основном есть два решения: "не очень" и "уродливо". Оба они о WeakReference.

# 1 Непростое решение - создать класс, который будет принимать слабый реф

class ApiRetryCallback(activity: Activity): RetryCallback(NUMBER, DELAY) {

    private val weakActivity = WeakReference(activity)

    override fun onRetry(retryCount: Int) {

        weakActivity.get()!!.mySdkApi.applicationStartup(this) //or weakThis.get()? to swallow null cases
    }

    override fun onCompleted(): Boolean {
        weakActivity.get()!!.updateStatus(Callback.Status.StartUpSDK)

        return true
    }

    override fun onFailed(e: MyException?) {
        weakActivity.get()!!.updateStatus(Callback.Status.StartUpSDK, "", e)
    }
}

В действии:

private val startupCallback = ApiRetryCallback(this) //this is MainActivity here

# 2 Уродливое решение основано на том факте, что лямбда-выражения должны захватывать родительскую ссылку, только там, где она используется напрямую.Итак, я придумал эту замену и не увидел сильных ссылок в отладчике, но вы должны проверить, что:

private val startupCallback = {
    val weakActivity = WeakReference(this@MainActivity)

    object : RetryCallback(NUMBER, DELAY) { //returned as last expression

        override fun onRetry(retryCount: Int) {

            weakActivity.get()!!.mySdkApi.applicationStartup(this) //or weakThis.get()? to swallow null cases
        }

        //....else methods....
    }

}()

Здесь лямбда будет вызываться немедленно и будет захватывать только слабые ссылки внутри объектаТакже он вернет последнее выражение, которое является объектом.

# 3 Пока я писал, я нашел третье решение, близкое к # 2

private val startupCallback = WeakReference(this).let { //this here is MainActivity
    val weakActivity = it //it of let scope wich is WeakReference

    object : RetryCallback(NUMBER, DELAY) { //returned as last expression

        override fun onRetry(retryCount: Int) {

            weakActivity.get()!!.mySdkApi.applicationStartup(this) //or weakThis.get()? to swallow null cases
        }

        //....else methods....
    }

}
0 голосов
/ 30 ноября 2018

Анонимные классы (как и ваши) не являются статичными.Вы можете заменить анонимный класс обычным классом (просто создайте класс с расширением RetryCallback) и передать все необходимые объекты в качестве аргументов конструктора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...