Pull to refresh

Comments 13

Единственным решением остается передавать слабую ссылку (или создавать внутри) в другой объект, который не подвержен жизненному циклу компонента (в нашем случае объект класса Api):

Да, другой класс должен быть не anonymous, но разве его нельзя сделать static inner?


А если использовать lambda из Java 8, последние версии android studio вроде имеют
неплохую поддержку java 8?

Смысл в том, чтобы обрабатывать асинхронные вызовы в одном месте кода. Не вижу решения проблемы через static inner (или просто static) классы.

Поизучал лямбды в Java 8. Они действительно ведут себя лучше, чем анонимные классы, т.е. захватывают контекст только по потребности. Обновлю статью.
У меня возникло несколько вопросов:
1) А причем тут Kotlin?
-Обертки вокруг сильных ссылок появились в Java с 1.2 версии и вы просто сделали «те же яйца но на котлиновских референсах». Просто тема уже изжеванная.

2) Зачем пытаться изобрести велосипед и изначально выбирать не правильное решение по способу загрузки. Простейший MVP решит все ваши проблемы с уничтожением View.

3) Если я не ошибаюсь, то очистка WeakRef происходит с вызовом GC.

val thisRef = WeakReference(this) // слабая ссылка на Activity
        api.getComments { list, exception ->
            val `this` = thisRef.get() // получаем Activity или null

Что то может пойти не так…

4) Extention functions
fun <T>T.weak() = WeakReference(this)

Предположим у меня небольшой проект с очень качественным single resposibility. Как скажется данный подход на вашем DexCount?

btw, я не являюсь адептом java или kotlin. Использую и то и другое в продакшене. Последний проект был целиком написан на kotlin. Но все же это просто инструмент (с более низким порогом вхождения после swift).

1) Возможно, стоило озаглавить "… в Java и Kotlin". Конечно, получилось вроде "безопасная обработке асинхронных вызовов в той же части кода, в которой этот вызов был совершен", но это немного жирно для заголовка. Да и тут представлен именно подход.


2) MVP — это еще одно равноправное решение данной проблемы. В своем проекте я использую Clean Architecture (VIP). Очень удобно декларировать слабую ссылку того же презентора на view через делегирование:


var view by weak<View>()

В Swift я бы написал


weak var view: View?

3) thisRef в лямбду захватывается сильной ссылкой. Очистится ли сама ссылка? Cложно поверить, что GC очистит слабую ссылку на валидный объект.


4) По-хорошему количество новых методов соответствовать количеству разных классов, на объектах которого вызывается данный метод.


все же это просто инструмент

Согласен.

Удивлен что не было упомянуто решение "в Kotlin стиле" — завернуть все эту логику с ссылками в одну функцию:


api.getCommentsWeakRef { list, exception ->
    if (list != null)
        updateUI(list)    // the methods are called on a weak reference
    else
         displayError(exception!!)
}

Сделаю по принципу Брежнева — кругом хвалят — надо попробовать Kotlin

Уже два года как люди используют RxJava. Отписываешься в onDestroy и порядок. Да, разбиение на маленькие классы помогает от утечек памяти в том числе.

С weak-ом такое вот решение еще можно, если уже котлин использовать:
class WeakContext<T>(self: T) {

    private val reference = WeakReference(self)

    val self: T?
        get() = reference.get()

    inline fun <R> ifSelfDefined(body: T.()->R): R? = self?.let(body)

}

inline fun <T, R> T.weakable(body: WeakContext<T>.()->R): R = WeakContext(this).body()

class Test {

    fun someMethod() = weakable {
        api.getComments { list, exception ->
            ifSelfDefined<Unit> {
                if (list != null)
                    updateUI(list)
                else
                    displayError(exception!!)
            }
        }

    }

}
понял, что контекст не нужен, т. е. еще проще:
inline fun <T, R> T.weakable(body: WeakReference<T>.() -> R): R = WeakReference(this).body()

inline fun <T, R> WeakReference<T>.ifSelfDefined(body: T.() -> R): R? = get()?.let(body)

class Test {

    fun someMethod() = weakable {
        api.getComments { list, exception ->
            ifSelfDefined {
                if (list != null)
                    updateUI(list)
                else
                    displayError(exception!!)
            }
        }

    }

}

и что важно, совершенно бесплатная абстракция выходит, как если бы мы сохраняли ссылку перед вызовом
Подход хороший, только вот пример совсем неудачный, не надо так работать с активити :)
UFO just landed and posted this here
Интересные примеры работы со слабыми ссылками, но нужно отметить принципиально неправильный подход в реализации и использовании API. Activity должна отменять любые (сетевые) операции после своего завершения. Если следовать этому правилу, то не будет необходимости в использовании слабых ссылок.
Правда при таком подходе будут отменятся также операции при изменении конфигурации, но это уже другая тема.
Sign up to leave a comment.

Articles