
Roman
07.04.2017
16:13:28

Boris
07.04.2017
16:14:33
да, не, это совсем не сложно

Google

Boris
07.04.2017
16:18:22
в 1.1 появилась еще вот такая штука, возможно окажется полезной как раз для твоего случая
https://kotlinlang.org/docs/reference/delegated-properties.html#providing-a-delegate-since-11

Roman
07.04.2017
16:25:27

Boris
07.04.2017
16:26:55
а %-)
еще вот такой вариант приходит в голову, хорош если таких значений несколько
class Tmp {
private val hook = Hook()
private val value: String by DisposableLazy(hook) { someExpression() }
fun onDispose() {
hook.dispose()
}
}

Liverm0r
07.04.2017
16:48:48
и упадет, если null, и не надо !! писать

Sergey
07.04.2017
16:49:51

Liverm0r
07.04.2017
16:51:58
s?.let { v: View ->
// ....
}?: throw SomeException()
вот так заработает

Sergey
07.04.2017
16:55:43
тогда в let что-то нужно вернуть

Liverm0r
07.04.2017
16:56:46
ну вот
var s: String? = null
fun f() {
s?.let {
ss: String ->
println("whatever")
}?: throw Exception()
}

Roman
07.04.2017
16:59:41

Google

Liverm0r
07.04.2017
17:00:12
там еще гарантия есть, что внутри let твой объект никто не занулит (с другого потока)
не нужно каждый раз ставить !!, обращаясь к нему

Roman
07.04.2017
17:01:37

Liverm0r
07.04.2017
17:02:42
s = s?.apply { s + "_"} ?: throw

Roman
07.04.2017
17:03:26

Liverm0r
07.04.2017
17:04:27
еще вижу проблему, если несколько полей)
так, может
class Holder{
val s: String = ""
val s2: String = ""
}
var holder: Holder? = null
fun f() {
holder?.let {
print(it.s)
print(it.s2)
}?: throw Exception()
}
Если с делегетами что-то придумаешь, пиши, интересно посмотреть)

Roman
07.04.2017
17:05:24

Valeriy
07.04.2017
17:08:39
А в kotlin android extentions разве нет штук для этого?

Михаил
07.04.2017
17:20:53

Boris
07.04.2017
17:37:34

Диёр
07.04.2017
17:46:19
Почему в джаве не реализованы фичи котлин для работы с ui в андроид? Это так сложно?

Roman
07.04.2017
18:03:54

Boris
07.04.2017
18:08:37
тогда можно эмулировать эцсамое типа такого
class Wrapper<T> {
private var value:T? = null
operator fun invoke():T = value ?: throw IllegalStateException()
fun clean() {
value = null
}
}
class Tmp {
private val value = Wrapper<String>()
fun someMethod() {
value().substring(10)
}
fun onDispose() {
value.clean()
}
}
выглядит как метод, но всё инкапсулировано во враппере

Roman
07.04.2017
18:12:40
синтаксис метода это конечно немного странно будет в коде =)
эх, был бы доступ к делегату проперти без сохранения его отдельно..

Google

Boris
07.04.2017
18:15:55
да, и вообще это можно сделать
через рефлекшн
но я пробовал, хорошего решения всё равно не выходит

Roman
07.04.2017
18:19:20
кажется я придумал простейшее решение как проверить что поле не инициализировано - нужно сделать экстеншн метод который читает его значение и ловит правильный тип эксепшена
так можно сделать один объект который предоставляет делегаты и сохраняет их у себя
сам этот объект сделать с lazy инициализацией в базовом классе фрагмента

Boris
07.04.2017
18:20:14
настоятельно не рекомендую делать глобальное состояние

Roman
07.04.2017
18:20:15
тогда в конкретном фрагменте все будет выглядеть идеально

Boris
07.04.2017
18:20:39
потому что это дорога в ад

Roman
07.04.2017
18:21:17
что ты имеешь в виду? =) глобавльное оно же только в рамках конкретного инстанса
одним вызовом все такие поля очистятся

Boris
07.04.2017
18:22:00
есть красота и удобство с одной стороны и нарушение инкапсуляции и вцелом хороших практик -- лучше чуть ужаться в первом на мой взгляд
может я тогда не понял, что ты предлагаешь
проверять что поле не инициализировано эксепшеном тоже идея на мой взгляд так себе


Roman
07.04.2017
18:27:25
class DisposablePropertyManager {
private val propertyDelegates: ArrayList<RegularDisposableVar<*>> = ArrayList()
fun <T : Any> disposable(): ReadWriteProperty<Any?, T> {
return RegularDisposableVar<T>().apply { propertyDelegates.add(this) }
}
fun dispose() {
for (delegate in propertyDelegates) {
delegate.dispose()
}
}
}
private class RegularDisposableVar<T : Any>() : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
fun dispose() {
value = null
}
}
использование:
private val disposableManager: DisposablePropertyManager by lazy { DisposablePropertyManager() }
private val feedListAdapter: MyFeedListAdapter by disposableManager.disposable()
первую строку можно положить в базовый класс
примерно так

Google

Roman
07.04.2017
18:30:28
если в сам делегат еще навернуть лямбду как у lazy то получим ленивую инициализацию
а дальше дилемма - можно делать инициализацию всегда когда value == null
тогда в общем-то без всяких проверок эксепшенов все будет работать
только вот если что-то попутать, то вместо эксепшена получим инициализацию и последующий меморилик
а можно безусловную иницализацию не делать и кидать таки эксепшен, но тогда нужно как-то проверить что поле еще не инициализировано
как это сделать кроме как через эксепшен лаконично я пока не придумал

Boris
07.04.2017
18:33:42
чота мне кажется, что черезмерная сложность для такой задачи, мы же на котлине пишем! ?

Roman
07.04.2017
18:35:10
еще можно на DisposablePropertyManager сделать метод init, который либо заставит все пропет=рти инициализироваться, либо просто разрешит им это сделать лениво без эксепшена. тогда между dispose и init эксепшен будет кидаться как задумано

Admin
ERROR: S client not available

Boris
07.04.2017
18:36:06
а ты понимаешь что бессмысленно делать лейзи disposableManager?

Roman
07.04.2017
18:36:36

Boris
07.04.2017
18:36:40
не только потому что непонятно зачем, но и потому что он сразу инициализируется как только ты его используешь для создания другог делегата
ну я же вроде предложил пару решений для их исключения, но вцелом если в одном классе может быть много таких полей, которые надо диспозить, то вполне ок
только я бы еще из списка делегаты тоже удалял

Roman
07.04.2017
18:38:19

Boris
07.04.2017
18:41:06
а, они еще и многоразовые

Roman
07.04.2017
18:41:44

Boris
07.04.2017
18:41:53

Roman
07.04.2017
18:42:46
ну учитывая что by lazy мы не боимся испорльзовать не вижу проблем такое использовать

Google

Roman
07.04.2017
18:43:06
работает оно просто и лежит просто в одном месте кушать не просит
не до конца чисто конечно, но имхо лучше чем ничего

Boris
07.04.2017
18:43:38
да, вполне ок решение

Roman
07.04.2017
18:44:01
вариант с Wrapper тоже хороший, но на мой вкус внутри кода будет уж больно необычно смотреться (как метод)

Boris
07.04.2017
18:45:07
я бы наверное что-то вроде него выбрал. или с хуками, что по сути тоже самое, что предложил ты, только не надо список хранить
тоесть просто вытащить наружу хвост, чтобы за него дергать когда хочется всё очистить

Roman
07.04.2017
18:46:31

Boris
07.04.2017
18:47:09
не, я там выше присылал вариант с хуком
class Tmp {
private val hook = Hook()
private val value1: String by DisposableLazy(hook) { someExpression() }
private val value2: String by DisposableLazy(hook) { someExpression() }
fun onDispose() {
hook.dispose()
}
}

Roman
07.04.2017
19:12:06

Boris
07.04.2017
19:12:44
Я так и сказал?

Roman
07.04.2017
19:12:58
=)
получилось даже круче чем я ожидал
меняешь во фрагменте lazy на disposableLazy и все - поле будет очищенно и востановлено в нужный момент жизненного цикла
больше во фрагменте никакого кода не меняется
спасибо всем кто помогал идеями!

Viktor
07.04.2017
21:33:41
только знакомлюсь с котлин, подскажите
вот код синглтона, вызов Singleton.instance будет потокобезопасным?
class Singleton private constructor(){
companion object {
val instance: Singleton = Singleton()
}
fun fooBar(){/** Some singleton function */}
}

Андрей
07.04.2017
21:48:52
а чем не устраивает
object Singleton {
fun fooBar(){/** Some singleton function */}
}