Привет, Хабр. В преддверии старта курсов "Android Developer. Basic" и "Android Developer. Professional" подготовили перевод материала.


Когда вы используете Android Java API в Kotlin, к вам достаточно быстро приходит понимание, что вам не хватает некоторых фич Kotlin, которые делают написание кода намного проще и приятнее. Вместо того, чтобы писать свои собственные обертки и функции расширения для этих API, я рекомендую вам обратить внимание на набор библиотек Jetpack KTX. В настоящее время более 20 библиотек имеют собственную KTX версию, создающую прекрасные идиоматические версии Java API, начиная от API платформы Android до ViewModels, SQLite и даже Play Core. В этой статье мы рассмотрим некоторые из доступных нам API и заглянем под капот, чтобы увидеть, как они были созданы.

Если вы предпочитаете чтению просмотр видео, вы можете ознакомиться с материалом этой статьи здесь:

Обнаруживаемость

Чтобы повысить обнаруживаемость функциональности ktx, рекомендуется всегда импортировать артефакт -ktx, если он доступен. Поскольку артефакт -ktx транзитивно зависит от не-ktx версии, вам не нужно включать другой артефакт. Например, для viewmodel у вас есть 2 артефакта: viewmodel и viewmodel-ktx. Артефакт -ktx будет содержать расширения Kotlin:

// Java language implementation
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// Kotlin implementation
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

Всегда импортируйте артефакт -ktx 

Для расширений API платформы Android следует импортировать артефакт core-ktx.

implementation "androidx.core:core-ktx:$corektx_version"

Большинство функций ktx реализовано как функции расширения, поэтому вы сможете легко найти их с помощью автокомплита в Android Studio.

Другие функции, такие как деструктуризация и перегрузка операторов, доступные в таких классах, как Color, можно обнаружить в списке расширений KTX.

API платформы — core-ktx

core-ktx обеспечивает идиоматическую функциональность Kotlin для API платформы Android.

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

/* Copyright 2020 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
   
- val editor = sharedPreferences.edit()
- editor.putBoolean(SHOW_DELETED_WORDS_KEY, enable)
- editor.apply()
+ sharedPreferences.edit {
+ putBoolean(SHOW_DELETED_WORDS_KEY, enable)
+ }

SharedPrefs.kt.diff на GitHub

Под капотом метод edit ktx вызывает ту же функциональность, по умолчанию предоставляя лучшую альтернативу commit — apply(). apply (), в отличие от commit(), фиксирует изменения на диске асинхронно:

// From https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:core/core-ktx/src/main/java/androidx/core/content/SharedPreferences.kt;l=39?q=SharedPreferences.kt

public inline fun SharedPreferences.edit(
    commit: Boolean = false,
    action: SharedPreferences.Editor.() -> Unit
) {
    val editor = edit()
    action(editor)
    if (commit) {
        editor.commit()
    } else {
        editor.apply()
    }
}

SharedPreferences.kt на GitHub

В core-ktx вы также можете найти более простой способ работы с часто используемыми листнерами платформы. Например, если вы хотите триггерить экшн по изменению текста в EditText, вам придется реализовать все методы TextWatcher, даже если вас интересует только onTextChanged(). core-ktx создает соответствующие методы TextWatcher: doOnTextChanged, doAfterTextChanged и doBeforeTextChanged, но в вашем коде Kotlin вы просто используете тот, который вам нужен:

/* Copyright 2020 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
   
- editWordView.addTextChangedListener(object : TextWatcher {
-     override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-         handleTextChanged(s)
-     }
-
-     override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-     }
-
-     override fun afterTextChanged(s: Editable) {
-     }
- })
+ editWordView.doOnTextChanged { text, start, count, after -> handleTextChanged(text) }

Edit.kt.diff на GitHub

Это дает несколько преимуществ: ваш код становится читабельнее, поскольку он лаконичнее, и вы получаете лучшие аннотации именования и nullability.

Вы можете найти похожие API листнеров для AnimatorListener и TransitionListener.

Под капотом doOnTextChanged реализован как функция расширения TextView — класса, который также имеет метод addTextChangedListener. doOnTextChanged создает пустые реализации для других функций TextWatcher.

API Jetpack

Большинство доступных расширений предназначены для API Jetpack. Здесь я просто рассмотрю некоторые из тех, которыми я пользовался чаще всего.

LiveData

Львиная доля функциональности LiveData также реализовано в виде функций расширения: такие методы как map, switchMap или distinctUntilChanged (источник).

Например, использование map из liveData-ktx избавляет нас от необходимости вызывать Transformations.map(liveata) { /* map function */ } и позволяет нам напрямую вызывать liveData.map более идиоматическим способом в духе Kotlin.

Когда вы наблюдаете за объектом LiveData, вам необходимо реализовывать Observer. Но с использованием метода observe из lifecycle-ktx код становится намного проще. Убедитесь, что вы вызываете импорт androidx.lifecycle.observe, если метод не найден.

/* Copyright 2020 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
   
- wordViewModel.allWords.observe(
-     this,
-     Observer { words ->
-         // Update the cached copy of the words in the adapter.
-         words?.let { adapter.submitList(it) }
-     }
- )
+ wordViewModel.allWords.observe(owner = this) { words ->
+     // Update the cached copy of the words in the adapter.
+     words.let { adapter.submitList(it) }
+ }

Observe.kt.diff на GitHub

LiveData идеально подходит для предоставления данных, которые будут использоваться пользовательским интерфейсом, поэтому для преобразования из Flow в LiveData и из LiveData в Flow, артефакт lifecycle-livedata-ktx предоставляет две удобных функций расширения: Flow.asLiveData() и LiveData.asFlow().

Activity / Fragment и ViewModel

Чтобы создать ViewModel, вы должны расширить класс ViewModel и реализовать ViewModelProvider.Factory, если ваша ViewModel имеет зависимости. Чтобы создать ее инстанс, используйте делегат viewModels (подробнее о делегатах вы можете почитать здесь): by viewModels(factory):

/* Copyright 2020 Google LLC.	
   SPDX-License-Identifier: Apache-2.0 */
   
+ private val wordViewModel: WordViewModel by viewModels {
+     WordViewModelFactory(repository)
+ }
override fun onCreate(savedInstanceState: Bundle?) {
…
-     val viewModelFactory = WordViewModelFactory(repository)
-     val viewModel = ViewModelProvider(this, viewModelFactory).get(WordViewModel::class.java)
}

MyActivity.kt.diff на GitHub

viewModels доступен в артефакте -ktx activity и fragment.

При работе с корутинами вы столкнетесь с необходимостью запускать корутину в ViewModel. Работа, выполняемая корутиной, должна быть отменена при уничтожении ViewModel. Вместо реализации своего собственного CoroutineScope, используйте viewModelScope. Отмена будет произведена автоматически в ViewModel.onCleared(). Вы можете узнайте больше о тонкостях viewModelScope в этой статье.

Room и WorkManager

И Room, и WorkManager предлагают поддержку корутин через свои артефакты -ktx. Поскольку мы считаем, что об этом стоит рассказать более подробно, следите за обновлениями статей MAD ??Skills, посвященных этим библиотекам!

Другие модули KTX

Артефакты AndroidX — не единственные, кто предоставляет KTX версии:

  • Google Maps предлагают Maps и Places библиотеки ktx

  • В Play Core есть артефакт core-ktx, обеспечивающий поддержку корутин для мониторинга обновлений в приложении

Лаконичность, удобочитаемость и Kotlin-идиоматичность — это фичи, которые принесут пользу вашему коду, как только вы начнете использовать -ktx расширения. Следите за новостями, чтобы узнать о других способах использовать Kotlin и Jetpack в своем приложении!

Узнать подробнее о курсах: "Android Developer. Basic" / "Android Developer. Professional".

Приглашаем также на открытые вебинары:
«Крестики-нолики на минималках» — игра на Android менее чем за 2 часа.

«Рисуем свой график котировок в Android»:
- Рассмотрим основные инструменты для рисования
- Изучим возможности классов Canvas, Path, Paint
- Нарисуем кастомизируемый график котировок и добавим в него анимации