#android #kotlin #android-workmanager
Вопрос:
Я хотел бы присвоить одно свойство либо лениво, либо «обычным способом», но проблема в том, что мое значение всегда равно «Любому». Я не могу использовать ключевое слово «by», когда я назначаю свойство условно. Вот мой нынешний подход
abstract class IWorkerContract(private val isLazy: Boolean = false) {
private val workRequest = if (isLazy) {
// Type mismatch. Required: OneTimeWorkRequest Found: Lazy<OneTimeWorkRequest>
lazy {
OneTimeWorkRequestBuilder<Worker>.build()
}
} else {
OneTimeWorkRequestBuilder<Worker>.build()
}
}
Редактирование Тестирования
abstract class IWorkerContract(private val isLazy: Boolean = false) {
private val lazyMgr = ResettableLazyManager()
private val workRequest by if (isLazy) {
// Type 'TypeVariable(<TYPE-PARAMETER-FOR-IF-RESOLVE>)' has no method 'getValue(Test, KProperty<*>)' and thus it cannot serve as a delegate
resettableLazy(lazyMgr) {
OneTimeWorkRequestBuilder<Worker>.build()
}
} else {
OneTimeWorkRequestBuilder<Worker>.build()
}
Ленивый делегат
class ResettableLazy<PROPTYPE>(
private val manager: ResettableLazyManager,
private val init: () -> PROPTYPE,
) : Resettable {
@Volatile
private var lazyHolder = initBlock()
operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE = lazyHolder.value
override fun reset() {
lazyHolder = initBlock()
}
private fun initBlock(): Lazy<PROPTYPE> = lazy {
manager.register(this)
init()
}
}
fun <PROPTYPE> resettableLazy(
manager: ResettableLazyManager,
init: () -> PROPTYPE,
): ResettableLazy<PROPTYPE> = ResettableLazy(manager, init)
Ответ №1:
значение всегда присваивается «Любому»
Да, потому что функция lazy { }
создает новый экземпляр Lazy<OneTimeWorkRequest>
, нет OneTimeWorkRequest
, эти типы несовместимы. Я не совсем понимаю ваши требования, но проблему можно решить, предоставив пользовательскую Lazy
реализацию, например
class InitializedLazy<T>(override val value: T) : Lazy<T> {
override fun isInitialized(): Boolean = true
}
Использование:
abstract class IWorkerContract(private val isLazy: Boolean = false) {
private val workRequest by if (isLazy) {
lazy { OneTimeWorkRequestBuilder<Worker>().build() }
} else {
InitializedLazy(OneTimeWorkRequestBuilder<Worker>().build())
}
}
Комментарии:
1. Это действительно работает, когда я использую kotlin по умолчанию «ленивый». Но когда я использую свой собственный «resettableLazy», я получаю ошибку. Я добавлю свой код
2. Может быть, вы можете добавить
isLazy
флаг вresettableLazy
функцию и изменитьinitBlock()
, например/* register */ return if (isLazy) { lazy { init() } } else { InitializedLazy(init()) }
3. @Andrew вы не следуете советам этого ответа. Обе ветви if/else должны возвращать делегата.
Ответ №2:
Вы могли бы разделить его на 2 отдельные переменные:
abstract class IWorkerContract(private val isLazy: Boolean = false) {
private val lazyWorkRequest by lazy {
OneTimeWorkRequestBuilder<Worker>.build()
}
private val workRequest
get() = when {
isLazy -> lazyWorkRequest
else -> OneTimeWorkRequestBuilder<Worker>.build()
}
}
Из get()
-за , lazyWorkRequest
будет инициализирован не сразу, а только при необходимости.
Но что еще более важно: зачем нужно такое поведение, в чем вред от постоянного использования lazy?
Кроме того, какова предназначенная цель ResettableLazy
? Похоже, все, что вы хотите иметь var
, и это решение для решения недостающего getValue()
или Type mismatch
. Это правильно?
Мне кажется, что ваш вопрос слишком специфичен, слишком техничен. Не могли бы вы объяснить, не используя Kotlin, какое поведение вам нужно?
Комментарии:
1. ResettableLazy-это делегат, значение которого вычисляется медленно, но может быть сброшено
Ответ №3:
Если вы получите доступ к своему свойству в конструкторе, оно будет вычислено во время создания экземпляра.
class Foo(val isLazy: Boolean){
val bar: Int by lazy { computeValue() }
init { if (!isLazy) bar }
}