16 советов по разработке для андроид на языке Kotlin. Часть 2

от автора

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

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


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

Описание объектов

Описания объектов допускают только синглетоны, которые нельзя принять за класс с возможностью создания экземпляров. Поэтому вам не нужно хранить синглеты как переменные статического класса или в классе Application.

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

package com.myapps.example.util import android.os.Handler import android.os.Looper // помните, что это объект, а не класс object ThreadUtil {     fun onMainThread(runnable: Runnable) {         val mainHandler = Handler(Looper.getMainLooper())         mainHandler.post(runnable)     } }

ThreadUtil можно вызвать позже таким же способом, как и при вызове метода статического класса:

ThreadUtil.onMainThread(runnable)

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

iewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {     override fun onPageScrollStateChanged(state: Int) {}     override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}     override fun onPageSelected(position: Int) {         bindUser(position)     } });

Оба по сути делают одно и то же — создают один экземпляр класса как объявленный объект.

Вспомогательные объекты

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

Взгляните на сопутствующий объект в его простейшей форме:

class User {     companion object {         const val DEFAULT_USER_AGE = 30     } } // к нему можно обратиться позже так: user.age = User.DEFAULT_USER_AGE

В Android мы обычно используем статические методы и переменные для создания статических фабрик для фрагментов. Например:

class ViewUserActivity : AppCompatActivity() {     companion object { const val KEY_USER = "user"         fun intent(context: Context, user: User): Intent {             val intent = Intent(context, ViewUserActivity::class.java)             intent.putExtra(KEY_USER, user)             return intent         }     }         override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_cooking)         val user = intent.getParcelableExtra<User>(KEY_USER)         //...     } }

Создание Intent похоже на аналогичное действие в Java:

val intent = ViewUserActivity.intent(context, user) startActivity(intent)

Этот паттерн хорош, так как он уменьшает вероятность того, что у Intent или Fragment будут отсутствовать необходимые для отображения пользовательского или любого другого контента данные. Сопутствующие объекты — это способ сохранить форму статического доступа в Kotlin, и их следует использовать как компенсацию отсутствия классов.

Глобальные константы

Kotlin позволяет вам определять константы, которые видны в одном месте приложения (если это применимо). Но область действия констант по возможности должна быть максимально уменьшена. А в ситуациях, когда нужно, чтобы область была глобальной, в Kotlin есть отличный способ сделать это без необходимости использовать класс констант. Что-то типа:

package com.myapps.example import android.support.annotation.StringDef // Это не класс, это объект! const val PRESENTATION_MODE_PRESENTING = "presenting" const val PRESENTATION_MODE_EDITING = "editing"

Потом их можно использовать как константы в любом месте проекта:

import com.savvyapps.example.PRESENTATION_MODE_EDITING val currentPresentationMode = PRESENTATION_MODE_EDITING

Констант в проекте должно быть как можно меньше, чтобы уменьшить его сложность. Если у вас есть значение, которое относится только к пользовательскому классу, лучше поместить его во вспомогательный объект.

Расширения

Расширения полезны, потому что они позволяют добавлять функциональность класса, не наследуя его. Например, как добавить к Activity какой-нибудь метод, типа hideKeyboard()? С помощью расширений можно легко это сделать:

fun Activity.hideKeyboard(): Boolean {     val view = currentFocus     view?.let {         val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager         return inputMethodManager.hideSoftInputFromWindow(view.windowToken,                 InputMethodManager.HIDE_NOT_ALWAYS)     }     return false }

Расширения полезны тем, что они:

  • помогают улучшить читабельность кода;
  • избавляют от необходимости создавать служебные классы и методы.

Можно пойти дальше и улучшить архитектуру кода. Представьте, что у вас есть базовая модель, например, Article, которая рассматривается как класс данных, извлеченных из источника по API:

class Article(val title: String, val numberOfViews: Int, val topic: String)

Нужно определить релевантность Article для пользователя на основе какой-то формулы. Должны ли вы поместить её непосредственно в класс Article? И если модель должна содержать только данные из API, не более того, снова можно использовать расширения:

fun Article.isArticleRelevant(user: User): Boolean {     return user.favoriteTopics.contains(topic) }

В настоящее время это простая возможность проверки присутствия темы Article в списке любимых тем пользователя.

Эта логика может меняться в зависимости от того, где вы хотите проверить эти и другие атрибуты пользовательского поведения. Поскольку эта логика поддерживается в некоторой степени независимо от модели Article, вы можете изменить ее в зависимости от цели, метода и его способности быть измененным.


ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/480534/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *