Комментарии 13
Единственным решением остается передавать слабую ссылку (или создавать внутри) в другой объект, который не подвержен жизненному циклу компонента (в нашем случае объект класса Api):
Да, другой класс должен быть не anonymous, но разве его нельзя сделать static
inner
?
А если использовать lambda из Java 8, последние версии android studio вроде имеют
неплохую поддержку 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 и порядок. Да, разбиение на маленькие классы помогает от утечек памяти в том числе.
От Jack'а отказались.
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!!)
}
}
}
}
и что важно, совершенно бесплатная абстракция выходит, как если бы мы сохраняли ссылку перед вызовом
Правда при таком подходе будут отменятся также операции при изменении конфигурации, но это уже другая тема.
Kotlin для Android: упрощаем работу со слабыми ссылками в асинхронных вызовах