Перед прочтением этих советов вам желательно ознакомиться с документацией Kotlin и самостоятельно изучить язык на сайте try.kotlinlang.org. Поскольку эти советы направлены именно на использование Kotlin в контексте разработки под Android, у вас также должен быть опыт работы с Android SDK. Также желательно ознакомиться с плагином Kotlin и использованием Kotlin с Android Studio от JetBrains (создателей Kotlin)

Базовые советы Kotlin для Android


Ленивая Загрузка


Ленивая загрузка имеет ряд преимуществ. Например таких:

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

Например, если вы создаёте приложение для покупок, в котором пользователи будут преимущественно руководствоваться вашим выбором, то ленивую загрузку можно настроить на API фактических покупок, например что-то типа этого:

val purchasingApi: PurchasingApi by lazy {
    val retrofit: Retrofit = Retrofit.Builder()
            .baseUrl(API_URL)
            .addConverterFactory(MoshiConverterFactory.create())
            .build()
    retrofit.create(PurchasingApi::class.java)
}

Результатом использования такой ленивой загрузки будет то, что если пользователь не попытается оформить в приложении покупку, вы не будете её загружать и использовать невостребованные ресурсы.

Также ленивая загрузка хороший способ инкапсулировать логику инициализации, например:

val bounds: RectF by lazy { 
    RectF(0f, 0f, width.toFloat(), height.toFloat()) 
}

Как только сделан первый вызов, создается экземпляр RectF на основании текущей ширины и высоты представления, что избавляет нас от необходимости создавать отдельно и устанавливать этот объект.

Пользовательские геттеры и сеттеры


Для чтения пользовательских установок в языке Kotlin используется структурная модель с заданным пользовательским поведением для получения и установки полей. При использовании моделей для определенных каркасов, таких как Parse SDK, вы выбираете значения, не являющиеся локальными переменными класса, но которые извлекаются и хранятся при помощи пользовательского способа, например, из JSON.

Используя определенные пользователем методы получения и установки, мы можем упростить доступ, например:

@ParseClassName("Book")
class Book : ParseObject() {

    // getString() and put() - методы ParseObject
    var name: String
        get() = getString("name")
        set(value) = put("name", value)
    var author: String
        get() = getString("author")
        set(value) = put("author", value)
}

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

val book = api.getBook()
textAuthor.text = book.author

Теперь, если нужно перенести вашу модель с Parse на какой-либо другой источник данных, код практически не нужно менять.

Лямбда


Лямбды сокращают дублирование строк кода в исходном файле и позволяют использовать функциональное программирование. Хотя лямбды в настоящее время уже используются в Android, Kotlin выводит их на новый уровень, гарантируя, что вам не придется иметь дело с Retrolambda или менять способ настройки сборки.

Например, прослушивание файла будет выглядеть примерно так:

button.setOnClickListener { view ->
    startDetailActivity()
}

А вот так это работает и с возвращаемыми значениями:

toolbar.setOnLongClickListener { 
    showContextMenu()
    true
}

В Android SDK довольно часто возникает потребность в реализации одного из таких методов. Лямбда с этим справляется на ура.

Классы данных


Классы данных упрощают классы, автоматически добавляя методы equals(), hashCode(), copy() и toString(). Они проясняют, какие данные должны использоваться в модели, отделяя данные от логики.

Например, вот такой класс данных:

data class User(val name: String, val age: Int)

Вот и все. Больше ничего не нужно для его работы. Если вы используете классы данных с чем-то похожим на Gson или другой библиотекой типа JSON, вы можете создать конструктор по умолчанию со значениями по умолчанию, например:

data class User(
    @SerializedName("name") val name: String = "",
    @SerializedName("age") val age: Int = 0
)

Фильтрация наборов данных


В работе с API постоянно возникает необходимость обработки коллекций. Чаще всего их нужно фильтровать или изменить содержимое.

Используя фильтрацию коллекций Kotlin, можно сделать код более простым и понятным. Задать содержимое списка результатов можно с помощью фильтрации коллекций, например так:

val users = api.getUsers()
val activeUsersNames = items.filter { 
    it.active
}
adapter.setUsers(activeUsers)

Встроенные методы фильтрации коллекций Kotlin очень похожи на методы, используемые в других языках программирования по типу Java 8 или при работе с типами коллекций Swift. Унифицированные способы фильтрации коллекций упрощают взаимопонимание при общении с сотрудниками по поводу необходимости выполнения конкретных операций для получения и отображения нужных списков элементов.

На этом мы завершаем первую часть статьи и приглашаем вас посетить бесплатный вебинар по теме: «Unit-тестирование в Android».

Комментарии (7)


  1. dimskiy
    09.12.2019 23:12
    +3

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


    1. rogrom
      09.12.2019 23:37
      +1

      еще и разбито будет на 40 частей


  1. anegin
    09.12.2019 23:47

    Например, прослушивание файла будет выглядеть примерно так:
    button.setOnClickListener

    что?
    почему фильтрация отдельным пунктом, почему не любая другая extenstion-функция для коллекций из десятков имеющихся?
    геттеры/сеттеры, дата классы, делегаты — это же просто базовый синтаксис котлина, а не какие-то пасхалки, скрытые в недрах


  1. jericho_code
    10.12.2019 11:25

    Для чего вы указываете @SerializedName(«name») если имя переменной и так name (как минимум в случае с Gson это излишне, или я что-то упускаю)?  Если из-за proguard, то проще уже было бы весь класс "@Keep" пометить.


    1. ChPr
      10.12.2019 12:37

      @Keep это не только про обфускацию, но и про оптимизацию тоже. Например, геттеры могут быть удалены и заменены прямой работой с полем класса. Может в R8 еще каких-нибудь оптимизаций добавят (или уже добавили).


    1. Neikist
      10.12.2019 13:56

      При будущем возможном рефакторинге может помочь.


  1. oldd
    10.12.2019 21:49

    К котлине очень делегаты радуют )
    class PlanPolygon(): Refreshed, ObservableList by observableArrayList()