И еще раз здравствуйте! В преддверии старта базового курса по Android-разработке, делимся заключительной частью статьи «16 советов по разработке для андроид на языке Kotlin».




Читать первую часть
Читать вторую часть

LATEINIT


Одной из ведущих особенностей Kotlin является его приверженность нулевой безопасности. Оператор lateinit предоставляет простой способ обеспечить нулевую безопасность и инициализировать переменную так, как этого требует Android. Эта функция прекрасна, тем не менее, к ней следует привыкнуть после работы на Java. Одна из идей заключается в том, что поле сразу объявляется с возможностью быть нулевым:

var total = 0 
var toolbar: Toolbar? = null


Эта языковая функция может вызвать сложности при работе с макетами Android, потому что мы не знаем как объявить представления, до того как макет объявлен, потому что неясно где они будут существовать, в Activity или Fragment. Это компенсируется при помощи дополнительных проверок на возможность нулевого значения в каждом месте, с которым мы взаимодействуем, но этот тот ещё геморрой. Поэтому лучше использовать модификатор lateinit:

lateinit var toolbar: Toolbar

Теперь вы, как разработчик, не должны ссылаться на Toolbar, пока она не будет фактически инициализирована. Это прекрасно работает, когда используется вместе библиотекой, например Butter Knife:

@BindView(R.id.toolbar) lateinit var toolbar: Toolbar
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ButterKnife.bind(this)
        // теперь можно без проблем обращаться к toolbar
        toolbar.setTitle("Hello There")
}

Безопасность типов


Некоторые соглашения Android требуют безопасной типизации, потому что обычная типизация не исключает ошибки кода. Например, типичный способ создания фрагмента в действии предполагает проверку через FragmentManager на исключение того, что он уже существует. И только если это не так, вы создадите его и добавите в действие. При первом взгляде на типизацию в Kotlin вы можете реализовать это следующим образом:

var feedFragment: FeedFragment? = supportFragmentManager
    .findFragmentByTag(TAG_FEED_FRAGMENT) as FeedFragment
но это может привести к сбою. Оператор as получит объект с нулевым значением, которое в данном случае исключено.
Правильный вариант такой:
var feedFragment: FeedFragment? = supportFragmentManager
    .findFragmentByTag(TAG_FEED_FRAGMENT) as? FeedFragment
if (feedFragment == null) {
    feedFragment = FeedFragment.newInstance()
    supportFragmentManager.beginTransaction()
            .replace(R.id.root_fragment, feedFragment, TAG_FEED_FRAGMENT)
            .commit()
}

LEVERAGING LET


Leveraging let позволяет вам выполнить блок, если значение объекта не равно нулю. Это позволяет вам избегать нулевых проверок и делает код более читабельным. В Java это выглядит так:

if (currentUser != null) {
    text.setText(currentUser.name)
}
А в Kotlin это выглядит так:
user?.let {
    println(it.name)
}

Этот код намного более удобный для чтения плюс автоматически создает переменную с ненулевым значением без опасности её обнуления.

SNULLOREMPTY | ISNULLORBLANK


Мы должны проверять поля много раз на протяжении разработки приложения для Android. Если вы справились с этим без использования Kotlin, возможно, вы знаете про класс TextUtils в Android. Класс TextUtils выглядит следующим образом:

if (TextUtils.isEmpty(name)) {
    // тут информируем пользователя
}

В этом примере вы можно заметить, что пользователь может установить в качестве имени пользователя даже просто пробелы, и он пройдет проверку. isNullOrEmpty и isNullOrBlank встроены в язык Kotlin, устраняют необходимость в TextUtils.isEmpty (someString) и обеспечивают дополнительное преимущество проверки только пробелов. Вы можете использовать при необходимости что-то типа такого:

// Если нам не важны пробелы в имени...
if (number.isNullOrEmpty()) {
// Просим пользователя ввести имя
}
//если пробелы критичны...
if (name.isNullOrBlank()) {
 // Просим пользователя ввести имя
}

Проверка правильности заполнения полей часто встречается при необходимости регистрации в приложении. Эти встроенные методы отлично подходят для проверки поля и оповещения пользователя, если что-то не так. Для более сложных проверок можно использовать методы расширения, например, для адресов электронной почты:

fun TextInputLayout.isValidForEmail(): Boolean {
    val input = editText?.text.toString()
    if (input.isNullOrBlank()) {
        error = resources.getString(R.string.required)
        return false
    } else if (emailPattern.matcher(input).matches()) {
        error = resources.getString(R.string.invalid_email)
        return false
    } else {
        error = null
        return true
    }
}

Советы для продвинутых


Вы знали, что для создания более чистого и лаконичного кода можете использовать лямбда-выражения?

Например, при работе в Java типично иметь простой класс прослушивателя, такой как:

public interface OnClickListener {  
    void onClick(View v);
}

Отличительной особенностью Kotlin является то, что он выполняет преобразования SAM (Single Abstract Method) для классов Java. Слухач кликов в Java, который выглядит как:

textView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // что-то делаем
    }
});
В Kotlin он может быть сокращён до:
textView.setOnClickListener { view ->
// что-то делаем
}

Как ни странно, такое преобразование невозможно для интерфейсов SAM, созданных в Kotlin. Это может удивить и даже немного разочаровать новых пользователей Kotlin. Если бы тот же самый интерфейс определен в Kotlin, слухач выглядит примерно так:

view.setOnClickListener(object : OnClickListener {
    override fun onClick(v: View?) {
       // что-то делаем
    }
})

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

private var onClickListener: ((View) -> Unit)? = null
fun setOnClickListener(listener: (view: View) -> Unit) {
    onClickListener = listener
}
// обращаемся у ним позже
onClickListener?.invoke(this)

Это вернет вас к простому лямбда-синтаксису, который делает возможным автоматическое преобразование SAM.

Заключение


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

На этом все. До встречи на курсе!

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


  1. anegin
    18.12.2019 19:10
    +2

    Пожалуйста, не продолжайте больше.
    "Слухач кликов" — это вообще шедевр.


  1. T0tem
    18.12.2019 22:01

    } else if (emailPattern.matcher(input).matches()) {
            error = resources.getString(R.string.invalid_email)
            return false
        }

    Почему тут invalid?


  1. adictive_max
    19.12.2019 08:02

    Переводить Null-safety как «нулевая безопасность» — это сильно. Ладно бы где-то в середине случайно затесалось, но прямо в первом-же абзаце, два раза… Вы после гугло-транслейта статью хотя бы на вычитку кому-нибудь отдаёте?


  1. adictive_max
    19.12.2019 09:11

    Если это читает кто-то из руководства OTUS, пожалуйста, увольте нафиг этих «рекламщиков», желательно пинком под зад с лестницы головой вниз.
    Присутствие на крупном IT-ресурсе статьи настолько отвратительного качества демонстрирует отсутствие у вас специалистов, способных написать даже простенький список «полезных советов». Как по вашему, насколько после этого будут доверять качеству ваших платных курсов? Такая халтура вам продажи только снизит.


    1. genbo
      19.12.2019 10:16

      Я вот к ним и решил не идти после первой статьи из этого цикла, хотя и тестирование уже прошел для поступления, и руки тянулись всё оплатить.


      1. MaxRokatansky Автор
        19.12.2019 10:50

        Это, конечно же Ваше решение. Но автор данной серии статей никак не связан с программой курса и не имеет к курсу никакого отношения


        1. adictive_max
          19.12.2019 11:41
          +1

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


          1. MaxRokatansky Автор
            19.12.2019 13:00

            Да, я согласен с Вами в том, что это совсем не оправдание. В дальнейшем будем тщательнее относиться к предоставляемому для публикации материалу.