@kotlin_lang

Страница 97 из 982
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
да, не, это совсем не сложно
я говорил про вариант с ViewHolder =)

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: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
ну вот var s: String? = null fun f() { s?.let { ss: String -> println("whatever") }?: throw Exception() }
а чем это лучше !!? длинее, читать тяжелее, делает тоже самое, разве нет?

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

не нужно каждый раз ставить !!, обращаясь к нему

Roman
07.04.2017
17:01:37
еще вот такой вариант приходит в голову, хорош если таких значений несколько class Tmp { private val hook = Hook() private val value: String by DisposableLazy(hook) { someExpression() } fun onDispose() { hook.dispose() } }
да, все это хорошо. вот только не понятно как потом переинициализировать свойство? т.е. к возможности снести надо еще иметь возможность переинициализировать перед новым использованием. а для этого вроде как нужно как-то суметь проверить disposed или нет

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
еще вижу проблему, если несколько полей)
да там вообще сплошные проблемы. nullable оправдан там где он есть. тут его по семантике нет, он есть только по нормам языка =)

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

Михаил
07.04.2017
17:20:53
А в kotlin android extentions разве нет штук для этого?
а там есть что-то кроме легкого юзанья разметки?

Boris
07.04.2017
17:37:34
да там вообще сплошные проблемы. nullable оправдан там где он есть. тут его по семантике нет, он есть только по нормам языка =)
Есть ещё уберпростое решение. Просто сделать нуллабл пропертю и ненулабл метод для её получения.

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

Roman
07.04.2017
18:03:54
Есть ещё уберпростое решение. Просто сделать нуллабл пропертю и ненулабл метод для её получения.
да, вариант неплохой. особенно если кода много, а полей мало. но вот если их много.. вот если бы можно было как макросом сразу и поле и гетер создавать одной строкой

А в kotlin android extentions разве нет штук для этого?
это штука чисто для обращения к вьюхам из лэйаута в коде. если только в недрах анко что-то есть

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
не только потому что непонятно зачем, но и потому что он сразу инициализируется как только ты его используешь для создания другог делегата
это нужно для тех фрагментов где нет disposable полей вообще. в базовом классе будет объявлен менеджер но он не будет создан

только я бы еще из списка делегаты тоже удалял
зачем? и как они потом снова туда попадут?

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

Roman
07.04.2017
18:41:44
а, они еще и многоразовые
ну да! фрагмент вью создал снова все работает =)

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
я бы наверное что-то вроде него выбрал. или с хуками, что по сути тоже самое, что предложил ты, только не надо список хранить

тоесть просто вытащить наружу хвост, чтобы за него дергать когда хочется всё очистить

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
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() } }
это очень похоже на мой вариант только управление инвертировано, если я правильно понимаю

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 */} }

Страница 97 из 982