Читать первую часть
Читать вторую часть
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. Надеюсь, знание этих советов существенно поможет вам в разработке собственных проектов.
На этом все. До встречи на курсе!
ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/481010/
Добавить комментарий