Simple android app kotlin

Пишем на Kotlin под Android

Года два назад я обнаружил, что в Android Market нет удобных мне приложений для учета времени, затраченного на разные проекты. Как настоящий лентяй, я решил не искать требуемое, а написать его сам. Это оказалось несколько сложнее, чем казалось вначале, и я все забросил в режиме вялотекущего хобби воплощение моего желания прожило больше года, медленно продвигаясь от идеи к альфа-версии.

И тут вдруг добрые люди предложили мне рассказать, как писать под Android на Kotlin’e. Мне показалось, что это добрый знак, и я быстро переписал приложение на Kotlin, закончил его и выложил в Google Play.

Важное уточнение: эта статья — только про то, как писать под Android на Kotlin’e. Интересно будет только тем, кто хочет попробовать Kotlin, и тем, кто хочет понять, зачем его пробовать. Приложение, которое я написал — очень-очень простое (и само по себе никак не относится к JetBrains). В его коде гарантированно можно что-то улучшить, оно выложено на Github только для примера, а не в качестве образца восхитительного кода. Оно работает, и если вам хочется его попробовать, то поставить можно отсюда. Но еще раз: это — демо, его цель — быть не совершенным приложением, а введением в Kotlin под Андроид.

Опять что-то новое. И зачем мне это знать?

Чтоб не оттягивать самое интересное, упомянем только самые главные преимущества Kotlin’a:

  • компактность кода. Быстро писать, легко читать, меньше наведенных ошибок;
  • встроенная защита от ошибок, прежде всего — nullability, т. е. требование к программисту явно указывать, что некая переменная может принимать значение null;
  • легкость в освоении (по-моему, даже начинающий разработчик на Java освоит Kotlin без труда).

На Kotlin’e можно писать значительно быстрее, чем на Jav’e, и код, на мой взгляд, получается более красивым.

Кстати, на github’e уже более 200 репозиториев с кодом на Kotlin’e, а если говорить про мобильные приложения, то Kotlin использовался при разработке мессенджера Telegram.

Ну ладно, а с чего начать-то?

Для работы потребуется IDE. Я по очевидным причинам предпочитаю IntelliJ IDEA, однако JetBrains делает плагин Kotlin и для Eclipse, а любители vim могут пользоваться отдельным компилятором языка.

Дальше будем предполагать, что все, кто пожелает попробовать Kotlin в деле под Android, будут использовать IntelliJ IDEA. Для работы понадобится установить плагин Kotlin и позаботиться, чтобы на компьютере были gradle и Android SDK (это к Kotlin’y отношения не имеет, это надо для разработки под Android на чем угодно).

Вначале была Java

У меня уже было частично написанное приложение, когда я решил довести его до конца. Все было написано на Java.

Суть приложения: на экране есть список красных задач, если кликнуть по задаче, она зеленеет, и время пошло: это значит, что пользователь работает над задачей. Как прекратил — кликает по ней еще раз, и задача снова краснеет, показывая, как немного времени он на нее потратил. Приложение слепо доверяет пользователю, не проверяя его никак: это вам не «большой брат смотрит за тобой» от oDesk’a.

То, что было написано на Java, я хотел переписать на Kotlin, душа просила кода на 100% на Kotlin, несмотря на то, что в одном проекте можно использовать код на Java и на Kotlin’e одновременно. Оказалось, что с унаследованным кодом все просто: рядом с src/main/java создаем папку src/main/kotlin, и в нее помещаем классы. Файлы в Kotlin’е заканчиваются не на .java, а на .kt. Тут к месту оказался приятный момент: Kotlin не требует соответствия «один класс — один файл». Можно в один файл запихнуть столько классов, сколько хочется по логике приложения. В моем приложении было всего две логических части — работа с базой данных и экранный интерфейс пользователя, так что количество файлов можно было сократить.

Читайте также:  Abc notes 4pda android

Плагин Kotlin к IntelliJ IDEA умеет конвертировать файлы .java в файлы .kt, выполняя аккуратную трансляцию из Java в Kotlin. Можно это делать через правый клик по файлу и контекстное меню, а можно — прямо при копировании кода на Java в файл .kt (плагин спросит, не сконвертировать ли).

Пишем код на Kotlin’e

Код на языке Kotlin компактен: например, класс вместе с конструктором и getters/setters описывается так:

Посмотрим на код, который создает диалог для ввода текста по клику на кнопку.

Согласитесь, код на Kotlin’e читается проще. Для внимательного читателя заметим, что это, конечно, только фрагмент кода, так как при создании диалога нужна не только кнопка «ОК», но и кнопка «Отмена». Полностью код выложен на Github.

Что дает возможность так сокращать код? Например, в Kotlin’e возможна такая форма записи: если где-то в качестве параметра ожидается экземпляр класса с одним абстрактным методом, туда можно просто передать лямбду: именно это и показано в примере выше.

Обратите внимание, что в Kotlin’e можно не указывать тип переменной, так как он будет выведен из правой части присваивания:

Java Kotlin
AlertDialog.Builder alert = new AlertDialog.Builder (this); val alert = AlertDialog.Builder(this)

Интересная особенность синтаксиса в Kotlin’e: если в функцию передаются параметры, и последний параметр — функция, то ее можно вынести за скобки. Именно это мы видим во фрагменте, где в setPositiveButton передается лямбда, которая сработает по нажатию кнопки «ОК»:

То же самое можно записать как

Вы вольны сами выбрать, какой вариант кажется проще для чтения.

Использование библиотек на Java в коде на Kotlin’e

Еще один приятный момент — возможность напрямую использовать библиотеки, написанные на Java, из кода на Kotlin.

Например, чтобы нормально обрабатывать спецсимволы и Unicode в названиях проектов при сохранении их в SQLite, я использовал функции StringEscapeUtils.escapeJava и StringEscapeUtils.unescapeJava из популярной библиотеки, которую достаточно импортировать оператором import (и вписать в зависимости в свойствах проекта):

Возвращаемое значение

В Kotlin в функциональных литералах (a.k.a лямбда-функциях) запрещено использовать return, так как функциональный литерал возвращает значение, вычисленное в последнем выражении. Так, в вызове setOnTouchListener ожидается, что последний параметр вызова — функция, возвращающая boolean. Это значение фактически возвращает gestureDetector.onTouchEvent(aEvent).

В коде функционального литерала на Kotlin нельзя писать return gestureDetector.onTouchEvent(aEvent), результат вызова gestureDetector.onTouchEvent(aEvent) и так будет возвращен.

На самом деле есть специальные случаи, когда в функциональном литерале следует использовать нелокальный return. Если интересно, подробности есть в документации по Kotlin

Аналогично работает возврат значений функциями, определенными через знак «=», вот так:

Строковые шаблоны

Чтобы избавиться от длинных строк, трудных для чтения и дающих неоптимальный байт-код, в Kotlin’e применены строковые шаблоны (string templates):

Здесь projectToDelete — это строковая переменная. Синтаксис такого шаблона привычен любому, кто имел дело с переменными среды в UNIX, например. Особенно удобны шаблоны для строк, составленных из текста и значений многих переменных, да еще и с форматированием:

Между прочим, с форматированием по ходу дела вышла интересная история: тип String в Kotlin — свой, и метода format в нем нет, поэтому пришлось импортировать java.lang.String.format явным образом и потом к нему так обращаться. Удивительно, кстати, что ни в Java, ни в Kotlin’e до сих пор нет метода secondsToHumanReadableString, преобразующего целое число секунд в строку формата

when и with

Очень удобно использовать when для множественного выбора и with для сокращения обращений к методам и свойствам — и того, и другого хватает даже в маленьком приложении под Android. В моем случае это давало более легкий в чтении код, например:

Без with получились бы alert.setPositiveButton, alert.setNegativeButton, alert.create, alert.show. When тоже повышает читаемость:

Компиляция с помощью Gradle

Если вы создаете build.gradle руками и/или собираете проект gradle’ом без IDE, то прочтите, как сдружить gradle, Kotlin и Android на сайте Kotlinlang.org.

Не знаю, есть ли такая проблема у пользователей Android Studio, но у привычного к IntelliJ IDEA человека работа с Gradle может вызвать вопрос, как собрать .apk для релиза, а не для отладки.

Для этого в IDEA есть плагин Gradle, открывается кликом по табу справа:

Читайте также:  Доктор веб для андроид инструкция

По умолчанию IDEA собирает *-debug-unsigned.apk, т.е. то, что в Google Play не положишь. Чтобы оно стало *-release-signed.apk, надо сгенерировать ключ для подписи, положить его в keystore, и вписать несколько строк в build.gradle вашего проекта, чтобы Gradle знал, где ключ взять. Для сборки release, выберите в окне Gradle задачу assembleRelease двойным кликом по ней.

Про то, как создавать ключ и подписывать приложение вы либо уже знаете, либо можете прочесть подробнее на stackoverflow.

На заметку

Недавно открылся наш новый сайт про Kotlin kotlinlang.org, который хостится на Jekyll+Github. Чем это решение хорошо, на Хабре недавно уже писали.

Если в статье какие-то примеры кода показались вам красивыми, то это — несомненная заслуга Натальи Ухорской, которая работает у нас в команде Kotlin. Я очень благодарен Наташе за советы, без которых эта статья оказалась бы короче, а код — менее похожим на классический Kotlin.

Мы будем очень рады, если сэкономленные за счет использования Kotlin часы вы сможете провести на пляже. Хорошего остатка лета!

UPD от 31.07.14, 18:55: поправлены некоторые термины и формулировки.

Источник

Создаём своё первое приложение для Kotlin Multiplatform

Авторизуйтесь

Создаём своё первое приложение для Kotlin Multiplatform

ведущий мобильный разработчик компании Usetech

В настоящее время мы переживаем бум появления новых технологий и подходов к написанию мобильных приложений. Одной из них является развивающийся SDK от компании JetBrains для мультиплатформенной разработки Kotlin Multiplatfrom (KMP) .

Основная идея KMP, как и других кросс-платформенных SDK — оптимизация разработки путем написания кода один раз и последующего его использования на разных платформах.

Согласно концепции JetBrains, Kotlin Multiplatform не является фреймворком. Это именно SDK, который позволяет создавать модули с общим кодом, подключаемые к нативным приложениям.

Написанный на Kotlin модуль компилируется в JVM байткод для Android и LLVM байткод для iOS.

Sportmaster Lab , Москва, Санкт-Петербург, Новосибирск, можно удалённо , По итогам собеседования

Этот модуль (Shared, Common) содержит переиспользуемую бизнес-логику. Платформенные модули iOS/Android, к которым подключен Shared/Common, либо используют написанную логику напрямую, либо имплементируют свою реализацию в зависимости от особенностей платформы.

Общая бизнес-логика может включать в себя:

  • сервисы для работы с сетью;
  • сервисы для работы с БД;
  • модели данных.

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

Концепцию Kotlin Multiplatform можно сравнить с реализацией Xamarin Native. Однако, в KMP нет модулей или функционала, реализующих UI. Эта логическая нагрузка ложится на подключенные нативные проекты.

Рассмотрим подход на практике и попробуем написать наше первое приложение Kotlin Multiplatform.

Для начала нам потребуется установить и настроить инструменты:

  1. Android Sdk
  2. Xcode с последним iOS SDK.
  3. Intelij IDEA CE или Android Studio. Обе IDE позволяют создавать и настраивать проекты для Kotlin Multiplatform. Но если в Intelij IDEA проект создается автоматически, то в Android Studio большую часть настроек надо сделать вручную. Если вам привычнее работать именно с Android Studio, то подробное руководство по созданию проекта можно посмотреть в документации на Kotlinlang.org

Мы рассмотрим создание проекта с помощью Intelij IDEA.

Выбираем меню File → New → Create Project:

В появившемся окне выбираем тип проекта Kotlin → Mobile Android/iOS|Gradle

Далее стандартно задаем путь к JDK, имя и расположение проекта

После нажатия кнопки Finish проект сгенерируется и будет почти готов к работе.

Рассмотрим, что у нас получилось:

Мультиплатформенные проекты Kotlin обычно делятся на несколько модулей:

  • модуль переиспользуемой бизнес-логики (Shared, commonMain и т.п);
  • модуль для IOS приложения (iOSMain, iOSTest);
  • модуль для Android приложения (androidMain, androidTest).

В них располагается наша бизнес-логика. Сам код базового примера мы разберем немного позже.

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

iOS приложение создается автоматически и располагается в каталоге iOSApp:

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

В local.properties зададим путь к SDK Android:

Создадим конфигурацию для работы Android приложения:

Теперь вызовем команду gradle wrapper для сборки нашего модуля общей логики:

После сборки модуль для бизнес-логики для Android приложения доступен в app/build/libs:

Путь к библиотеке прописывается стандартно, в блоке dependencies файла build.gradle:

Теперь наш проект сконфигурирован для запуска Android приложения:

Читайте также:  Не открывается навител для андроид

Осталось сделать настройки для запуска приложения iOS.

В файле build.gradle(:app) необходимо изменить настройку архитектура проекта, чтобы наше приложение поддерживало как реальные устройства, так и эмуляторы.

После выполнения сборки создастся фреймворк в app/build/bin/ios:

Intelij IDEA автоматически создает в gradle файле код для генерации, подключения и встраивания фреймворка в IOS проект:

При ручной настройке проекта (например, через Android Studio) этот код потребуется указать самостоятельно.

После синхронизации gradle iOS проект готов к запуску и проверке с помощью XCode.

Проверяем, что у нас получилось. Открываем проект iOS через iosApp.xcodeproj:

Проект имеет стандартную структуру, за исключением раздела app, где мы получаем доступ к коду наших модулей на Kotlin.

Фреймворк действительно подключен автоматически во всех соответствующих разделах проекта:

Запускаем проект на эмуляторе:

Теперь разберем код самого приложения на базовом примере.

Используемую в проекте бизнес-логику можно разделить на:

  • переиспользуемую (общую);
  • платформенную реализацию.

Переиспользуемая логика располагается в проекте commonMain в каталоге kotlin и разделяется на package. Декларации функций, классов и объектов, обязательных к переопределению, помечаются модификатором expect :

Реализация expect -функционала задается в платформенных модулях и помечается модификатором actual :

Вызов логики производится в нативном проекте:

Все очень просто.

Теперь попробуем по тем же принципам сделать что-то посложнее и поинтереснее. Например, небольшое приложение для получения и отображение списка новостей для iOS и Android.

Приложение будет иметь следующую структуру:

В общей части (Common) расположим бизнес-логику:

  • сетевой сервис;
  • сервис для запросов новостей.

В модулях iOS/Android приложений оставим только UI компоненты для отображения списка и адаптеры. iOS часть будет написана на Swift, Android – на Kotlin. Здесь в плане работы не будет ничего нового.

Организуем архитектуру приложений по простому паттерну MVP. Презентер, обращающийся к бизнес-логике, также вынесем в Common часть. Также поступим и с протоколом для связи между презентером и экранами UI:

Начнем с бизнес-логики. Т.к весь функционал будет в модуле common, то мы будем использовать в качестве библиотек решения для Kotlin Multiplatform:

1. Ktor – библиотека для работы с сетью и сериализации.

В build.gradle (:app) пропишем следующие зависимости:

Также добавим поддержку плагина сериализации:

2. Kotlin Coroutines – для организации многопоточной работы.

При добавлении зависимости в iOS проект обратите внимание, что версия библиотеки должна быть обязательно native-mt и совместима с версией плагина Kotlin multiplatform.

При организации многопоточности с помощью Coroutines необходимо передавать контекст потока ( CoroutineContext ), в котором логика будет исполняться. Это платформозависимая логика, поэтому используем кастомизацию с помощью expect / actual .

В commonMain создадим Dispatchers.kt, где объявим переменные:

Реализация в androidMain создается легко. Для доступа к соответствующим потокам используем CoroutineDispatchers Main (UI поток) и Default (стандартный для Coroutine ):

С iOS труднее. Та версия Kotlin Native LLVM компилятора, которая используется в Kotlin Multiplatform, не поддерживает background очереди. Это давно известная проблема, которая к сожалению, еще не исправлена

Поэтому попробуем обходной маневр как временное решение проблемы.

Мы создаем свой CoroutineDispatcher , где прописываем выполнение логики в асинхронной очереди dispatch_async .

Также нам понадобится свой scope для работы сетевого клиента:

iOS

Android

Применим это при реализации сетевого клиента на Ktor:

Парсинг реализуем с помощью сериализатора типа KSerializer . В нашем случае это NewsList.serializer() . Пропишем реализацию в сервисе новостей:

Вызывать бизнес-логику будем в презентере. Для полноценной работы с coroutines нам надо будет создать scope:

и добавить его в презентер. Вынесем в базовый класс:

Теперь создадим презентер NewsListPresenter для нашего модуля. В инициализатор передадим defaultDispatcher :

Обратите внимание! Из-за особенностей текущей работы Kotlin Native с многопоточностью в IOS работа с синглтонами может привести к крашу. Поэтому для корректной работы надо добавить аннотацию @ThreadLocal для используемого объекта:

Осталось подключить логику к нативным IOS и Android модулям и обработать ответ от Presenter:

Запускаем сборку common модуля gradle wrapper, чтобы сборки обновились. Проверяем работу приложений:

Готово. Вы великолепны.

Оба наши приложения работают и работают одинаково.

Информационные материалы, которые использовались:

Источник

Оцените статью