Intereting Posts
Не удалось загрузить ошибку класса kotlin.collections.CollectionsKT при попытке синхронизации градиента Kotlin – Сортировка MutableList на основе свойства объекта KTor или Spark? Какая продукция готова для веб-сервисов Kotlin? Каковы наилучшие методы для «обрезки» исключения stacktrace перед регистрацией с помощью SLF4J? Экземпляр экземпляра Kotlin имеет значение null при доступе к Spring-классу Spring Kotlin – Почему эта функция не подходит для рекурсии хвоста? Как полезна делегация Котлина? Ошибка: ошибка: разрешены только безопасные (?.) Или непустые (!!.) Вызовы в приемнике с нулевым значением типа View? IOException: AsyncTask Image Загрузить Kotlin Android (дескриптор Bad File) «Не удалось запустить активность» в тесте эспрессо Функциональное программирование: как переносить контекст для цепочки правил проверки Доступ к TextView в пользовательском классе в Котлине Вывод типа Kotlin не выполнен В чем разница между реализацией и компиляцией в gradle Почему прокрутка ViewPager перед тем, как изменить его заполнение и pagemargin, полностью подвела его?

Игнорировать setter и установить свойство напрямую

У меня есть класс, который записывает пользователя в SharedPreferences каждый раз, когда он установлен:

class UserManager @Inject constructor( val prefs: SharedPreferences, val jsonAdapter: JsonAdapter<User> ) { companion object { val USER = "user" } var user: User = User() set(value) { field = value prefs.edit().putString(USER, jsonAdapter.toJson(user)).apply() } init { val userString = prefs.getString(USER, null) if (userString != null) { user = jsonAdapter.fromJson(userString) } } } 

Проблема. Если пользователь установлен в блоке init, он вызывает установщика и записывает пользователя, которого мы только что получили из общих префов … в общие префы.

Вопрос 1: Как я могу прямо установить свойство из блока init?

Вопрос 2: Почему я должен инициализировать пользователя, когда я определяю настраиваемый наборщик, но могу опустить инициализацию, когда используется установщик по умолчанию?

Вам нужно прямо инициализировать свойство с правильным значением. Вы можете сделать это, используя функцию run из stdlib:

 class UserManager @Inject constructor( val prefs: SharedPreferences, val jsonAdapter: JsonAdapter<User> ) { companion object { val USER = "user" } var user: User = run { val userString = prefs.getString(USER, null) if (userString != null) { jsonAdapter.fromJson(userString) } else { User() } } set(value) { field = value prefs.edit().putString(USER, jsonAdapter.toJson(user)).apply() } } 

Более короткий синтаксис, предложенный Илья Рыженковым на Kotlin Slack:

 var user: User = prefs.getString(USER, null)?.let { jsonAdapter.fromJson(it) } ?: User() set(value) { field = value prefs.edit().putString(USER, jsonAdapter.toJson(user)).apply() } 

Я считаю, что лучшим решением является использование концепции «свойства поддержки», описанной здесь: https://kotlinlang.org/docs/reference/properties.html#backing-properties

 private var _table: Map<String, Int>? = null public val table: Map<String, Int> get() { if (_table == null) _table = HashMap() // Type parameters are inferred return _table ?: throw AssertionError("Set to null by another thread") } 

Затем инициализируйте свойство backing в конструкторе и сделайте <backingproperty> = value вместо <backingproperty> = value field = value а также укажите getter на свойство backing.

Взгляните на делегата by map , похоже, это шаблон, который вы хотите:

 class User(val map: MutableMap<String, Any?>) { var name: String by map var age: Int by map } 

https://kotlinlang.org/docs/reference/delegated-properties.html#storing-properties-in-a-map