Читать первую часть
Читать вторую часть
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)
T0tem
18.12.2019 22:01} else if (emailPattern.matcher(input).matches()) { error = resources.getString(R.string.invalid_email) return false }
Почему тут invalid?
adictive_max
19.12.2019 08:02Переводить Null-safety как «нулевая безопасность» — это сильно. Ладно бы где-то в середине случайно затесалось, но прямо в первом-же абзаце, два раза… Вы после гугло-транслейта статью хотя бы на вычитку кому-нибудь отдаёте?
adictive_max
19.12.2019 09:11Если это читает кто-то из руководства OTUS, пожалуйста, увольте нафиг этих «рекламщиков», желательно пинком под зад с лестницы головой вниз.
Присутствие на крупном IT-ресурсе статьи настолько отвратительного качества демонстрирует отсутствие у вас специалистов, способных написать даже простенький список «полезных советов». Как по вашему, насколько после этого будут доверять качеству ваших платных курсов? Такая халтура вам продажи только снизит.genbo
19.12.2019 10:16Я вот к ним и решил не идти после первой статьи из этого цикла, хотя и тестирование уже прошел для поступления, и руки тянулись всё оплатить.
MaxRokatansky Автор
19.12.2019 10:50Это, конечно же Ваше решение. Но автор данной серии статей никак не связан с программой курса и не имеет к курсу никакого отношения
adictive_max
19.12.2019 11:41+1Тем не менее, он публикуется в корпоративном блоге образовательной платформы и оставляет в конце рекламу ну курс, соответствующий тематике публикации. Этого вполне достаточно, чтобы создать негативное впечатление об объекте рекламы.
MaxRokatansky Автор
19.12.2019 13:00Да, я согласен с Вами в том, что это совсем не оправдание. В дальнейшем будем тщательнее относиться к предоставляемому для публикации материалу.
anegin
Пожалуйста, не продолжайте больше.
"Слухач кликов" — это вообще шедевр.