Встроенные делегаты для решения общих проблем

Сегодня я поделюсь некоторыми знаниями о Делегированной собственности в Котлине. Чтобы быть конкретным, я буду говорить только о трех из них - Lazy, Observable и Vetoable, которые могут помочь во многих общих проблемах.

Проще говоря, делегированное свойство - это свойство, при доступе к которому будет вызываться соответствующий метод getValue () или setValue ().

Kotlin предоставляет несколько встроенных в язык делегированных свойств - Ленивые свойства, Наблюдаемые свойства и Свойства, хранящиеся на карте.

У меня нет реального и подходящего варианта использования хранения свойств на карте (как объясняется в документации - «сохранение свойств на карте вместо отдельного поля для каждого свойства»), но Ленивый и наблюдаемый - это делегаты, активно используемые в повседневной работе.

Ленивая собственность

Часто бывает полезно отложить создание объекта до его первого использования. Подумайте о тяжелых объектах, которые могут повлиять на время запуска приложения или могут никогда не вызываться (например, в случае обработки событий щелчка).

Котлин предоставляет ленивого делегата, который заботится об ожидании создания фактического объекта до первого касания. При использовании метод getValue () оценивается, а результат запоминается.

private val model by lazy { Injector.app().transactionsModel() }
// Somewhere inside the function body
view.setOnClickListener { model.showWallets() }

Как показано выше, модель является делегированным свойством. Его тело инициализации будет вызываться только в случае вызова onClickListener. Что важно, он будет инициализирован только один раз.

Kotlin предоставляет 3 различных режима для определения политики потоковой передачи (СИНХРОНИЗИРОВАННЫЙ, ПУБЛИКАЦИЯ, НЕТ).

  • Режим LazyThreadSafetyMode.SYNCHRONIZED используется, чтобы гарантировать, что только один поток может инициализировать экземпляр.
  • LazyThreadSafetyMode.PUBLICATION позволяет нескольким вызывающим объектам вызывать тело инициализации, но только первое возвращенное значение будет использоваться в качестве значения.
  • LazyThreadSafetyMode.NONE не заботится о потоковой передаче, и для нескольких вызывающих объектов результат является неожиданным. Android работает со многими фреймворками, которые используются только в потоке пользовательского интерфейса. В таких случаях, используя LazyThreadSafetyMode.NONE, мы могли бы воспользоваться преимуществами Thread Confinement и сэкономить драгоценные миллисекунды для получения блокировок.

Чтобы указать политику потока, передайте значение LazyThreadSafetyMode в параметр lazy, как показано ниже:

private val model by lazy(mode = LazyThreadSafetyMode.NONE) { 
    Injector.app().transactionsModel() 
}

Наблюдаемое и разрешенное право собственности

Observable - это свойство с прикрепленным телом, которое вызывается после каждой модификации. Это позволяет иметь логически связанную бизнес-логику, открывая снаружи только собственность.

Vetoable имеет аналогичную концепцию, но также дает возможность блокировать изменения в зависимости от возвращаемого значения. Оба делегата создаются с использованием фабричной функции из Delegates.kt, как показано ниже:

// Adapter
var data: List<Any> by Delegates.vetoable(listOf()) { p, old, new ->
    notifyDataSetChanged()
    old != new
}
// Somewhere in the code...
adapter.data = model.fetchWallets()

При создании наблюдаемого или vetoable необходимо указать значение по умолчанию в качестве параметра. Когда вызывается обратный вызов onChange, разработчик может проверить текущее значение old (которое является значением по умолчанию при первом вызове), новое значение, которое назначается, а также p, который относится к измененному свойству.

Каждый раз, когда adapter.data устанавливает новое значение, вызывается лямбда onChange. Как упоминалось ранее, Vetoable может заблокировать модификацию, вернув false из тела лямбда (в приведенном выше примере, если предыдущее значение не было фактически изменено).

В примере показано простое использование реализации RecyclerView.Adapter. Чтобы избежать повторного назначения одного и того же значения (что потребовало бы переписывания представления), Vetoable проверьте, не совпадают ли предыдущее и новое значение.

Когда вызывается обратный вызов onChange Vetoable, он сначала проверяет возвращаемое значение. Когда ИСТИНА, тогда значение устанавливается на новое значение. Если вернуть FALSE, свойство не изменится.

Вот и все! Если вы хотите узнать больше, перейдите по ссылкам ниже для получения дополнительной информации.