Построение графиков android studio kotlin

Пишем MVP приложение на Kotlin под Android

Разработка приложений на Kotlin под Android набирает популярность среди разработчиков, однако статей в русскоязычном сегменте Интернета довольно мало. Я решил немного подправить ситуацию, и написать туториал по разработке приложения на Kotlin. Мы напишем полноценное приложение с использованием всех трендовых библиотек (кроме RxJava) в мире Android-разработки. В конце у нас должно получиться расширяемое и легко тестируемое приложение (сами тесты мы писать не будем).

Внимание! В статье описывается создание приложения версии 1.0. Текущий код в репозитории может отличаться от описываемого в статье.

Наверное, некоторые из вас знают, что помимо языка программирования Kotlin JetBrains также разрабатывает библиотеку Anko, для создания UI приложения, в качестве замены обычным XML-файлам. Мы не будем использовать его в нашем проекте, дабы не ставить в затруднительное положение людей не знакомых с Anko.

Настройка Android Studio

Для написания приложений на языке Kotlin, Android Studio нужен специальный плагин. Инструкцию по установке плагина можно найти здесь. Также не забудьте отключить функцию «Instant Run» в настройках Android Studio, т. к. на данный момент она не поддерживается плагином Kotlin.

Для корректной работы генерации кода нужно использовать версию плагина не ниже 1.0.1. Я использовал версию Kotlin 1.0.2 EAP. Вот так выглядит файл build.gradle приложения в моем проекте:

Что будем писать?

Итак, для начала нам нужно определиться что же мы будем писать? Недолго думая я остановился на приложении-заметках. Название тоже придумалось легко — Notelin. Приложение очень простое и состоит из двух экранов:

— Главный экран — содержит в себе список с заметками
— Экран заметки — здесь можно смотреть/редактировать содержание выбранной заметки

Требования к приложению небольшие:

— Добавление/просмотр/удаление заметки
— Просмотр информации о заметке
— Сортировка заметок по заголовку и по дате
— Поиск по заголовкам заметок

Используемые библиотеки

Для работы с базой данных я буду использовать библиотеку Android Active. Урок по работе с ней можно найти по этой ссылке. Для реализации Depency Injection была использована библиотека Dagger 2. На Хабре есть много статей по работе с ней. Основой всего приложения будет библиотека Moxy. С ее помощью мы реализуем паттерн MVP в нашем проекте. Она полностью решает проблемы жизненного цикла, благодаря чему вы можете не переживать о пересоздании компонентов вашего приложения. Также мы воспользуемся набором расширений для языка Kotlin в Android — KAndroid. Про остальные библиотеки я буду рассказывать по ходу дела.

Ниже приведен список зависимостей проекта:

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

Обратите внимание, что вместо apt я использую kapt. Это плагин для Gradle, позволяющий аннотировать Kotlin-элементы.

Структура приложения

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

Создаем Model

У заметок будет четыре поля:

  • Дата создания
  • Дата изменения
  • Заголовок
  • Текст

Реализуем все это в коде:

По этой модели библиотекой ActiveAndroid будет создана БД, в которой будут храниться наши заметки. Если вы заметили, у нас есть два конструктора: пустой и с параметрами. Первый конструктор будем использовать мы, а второй — ActiveAndroid. Наша модель наследуется от класса Model, благодаря чему мы можем сохранять и удалять наши заметки просто вызывая методы save() и delete(), например:

Но прежде чем использовать нашу модель, нам нужно прописать кое-какие мета-данные в Manifest-файле:

Думаю, все понятно без комментариев. Осталось унаследовать класс Application от com.activeandroid.app.Application:

Чтобы приложение было менее зависимо от БД я создал обертку NoteDao над нашей моделью, в которой будут происходить все операции по созданию, сохранению, обновлению и удалению заметок:

Наверное, вы заметили, что для создания объектов мы не использовали ключевое слово new — это отличие Kotlin от Java.

Экран с заметками

Также является главным экраном приложения. На нем пользователь может добавить/удалить заметку, просмотреть информацию о заметке, отсортировать их по дате или названию, а также произвести поиск по заголовкам.

Создаем MainView и MainPresenter

Теперь нам нужно перевести все это в код. Для начала создадим интерфейс нашей View:

Далее мы реализуем созданный интерфейс в нашей активити:

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

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

Пока оставим методы пустыми. Как видите, активити наследуется от MvpAppCompatActivity. Это нужно для того, чтобы активити могла восстанавливать состояние при повороте экрана.

Создадим класс презентер:

Презентер также наследуется от MvpPresenter, которому мы указываем с какой View мы будем работать.Осталось инжектировать нашу модель в презентер. Для этого мы создаем модуль — поставщика NoteDao:

Создадим Component для инжектирования презентера:

Теперь нам нужно создать статический экземпляр класса AppComponent в классе Application:

Читайте также:  Keyboard from android apk

Теперь мы можем инжектировать нашу модель в презентере:

Для взаимодействия MainView и MainPresenter нам нужно создать переменную в MainActivity:

Плагин Moxy сам привяжет View к фрагменту и произведет другие необходимые действия.

Создадим разметку экрана со списком и плавающей кнопкой. Файл activity_main.xml:

Для реализации летающей кнопки я использовал библиотеку FloatingActionButton. Google уже добавили FAB в support-библиотеку, поэтому вы можете воспользоваться их решением.

Укажем нашей Activity, какой макет она должна показывать:

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

Нам не нужно писать порядком надоевший findViewById, нужно лишь прописать одну строчку в блоке с import’ами:

Как видите, последний пакет совпадает с названием нашего xml-файла. IDE автоматически инициализирует свойства (property) наших View и их имена совпадают с ID, которые мы указали в разметке.

Давайте реализуем загрузку заметок из БД. Заметки нужно загружать только один раз и использовать их в последующем. В этом нам поможет метод onFirstViewAttach класса MvpPresenter, который вызывается единожды при первой привязке View к презентеру. Далее, сколько бы мы не крутили и вертели нашу Activity, данные будут закешированы в презентере.

Создадим адаптер для нашего списка:

В адаптере мы используем метод formatDate. Он служит для форматирования даты в строку:

Данный метод находится в файле DateUtils.kt и мы можем использовать как обычный статический метод. Отличие от статического метода здесь в том, что метод принадлежит не классу, а пакету и нам не нужно писать имя класса перед названием метода. В аннотации мы указываем название класса, через который мы будем обращаться к методу из Java. Например в Java дынный метод будет вызываться так:

В методе onNotesLoaded нашей Activity мы показываем наши заметки:

Если заметок нет, то мы показываем сообщение «Нет заметок» в TextView.

Насколько я знаю, для обработки клика по элементам RecycleView не существует «официального» OnItemClickListener. Поэтому мы воспользуемся своим решением:

В методе onCreate нашей Activity пишем:

Функция with позволяет не писать каждый раз имя переменной, а только лишь вызывать методы у объекта, который мы передали в нее. Обратите внимание, что для получения Activity я использовал не просто this, а this@MainActivity. Это связано с тем, что при использовании this в блоке with, возвращается объект, который мы передали в функцию with. При обычном клике по пункту мы переходим на Activity, где мы можем просмотреть текст нашей заметки. При долгом нажатии появляется контекстное меню. Если вы заметили, перед закрывающей скобкой я не написал слово return. Это не ошибка, а особенность языка Kotlin.

Вот что происходит при нажатии на пункт меню в презентере:

Мы еще не создали класс NoteActivity, поэтому компилятор будет выдавать ошибку. Для решения этой проблемы можно создать класс NoteActivity или вовсе закомментировать код внутри метода openNote. Запись NoteActivity::class.java аналогична NoteActivity.class в Java. Также заметьте, что мы обращаемся к списку не через метод get(position), а через квадратные скобки, как к обычному массиву.

При использовании MVP-библиотеки Moxy в своем приложении, нам нужно привыкать, что все действия с View, такие как показ/закрытие диалога и другие, должны проходить через презентер. Изначально это не очень привычно и неудобно, но пользы от этого гораздо больше, т. к. мы можем быть уверены, что при пересоздании Activity наше диалоговое окно никуда не пропадет.

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

При нажатии на FAB должна создаваться новая заметка:

Для создания новой заметки мы вызываем у презентера функция openNewNote:

Метод openNewNote использует созданный нами ранее openNote, в который мы передаем Context и позицию заметки в списке.

Реализуем поиск по заметкам

Давайте добавим поиск по заметкам. Создайте в папке res/menu файл main.xml:

В MainActivity пишем:

При изменении текста в поле поиска мы передаем строку из поля в презентер, после чего показываем результаты в списке. На самом деле, у SearchView нет метода onQueryChange, его добавила библиотека KAndroid.

Реализуем поиск в презентере:

Обратите внимание, как красиво, в одну строчку мы реализовали поиск по списку с помощью метода filter и лямбд. В Java тот же функционал занял бы 6-7строк. Осталось отобразить результаты поиска:

Реализуем сортировку заметок

И последний этап в создании главного экрана, это сортировка заметок. Добавим в res/menu/main.xml следующие строки:

Теперь нам нужно обработать нажатие на пункты меню:

Оператор when является более функциональным аналогом switch-case в Java. Код сортировки в MainPresenter:

Экран с содержанием заметки

Теперь нам нужно создать экран с содержанием заметки. Здесь пользователь может просмотреть/отредактировать заголовок и текст заметки, сохранить или удалить ее, а также просмотреть информацию о заметке.

Создаем NoteView и NotePresenter

Экран содержит всего лишь три View:

-Заголовок
-Дата последнего изменения
-Текст заметки

А вот и сама разметка:

В начале статьи я мельком упомянул об Anko. Библиотека позволяет существенно сократить код, не теряя при этом в удобочитаемости. Вот так, например, выглядела бы наша разметка при использовании Anko:

Но не будем отвлекаться и приступим к написанию кода. Первым делом нам нужно создать View:

Имплементируем NoteView в NoteActivity:

В onCreate мы извлекаем id заметки, чтобы презентер достал заметку из БД и передал данные во View. Создадим презентер:

Не забудьте добавить в класс AppComponent строку:

Покажем нашу заметку:

Реализуем сохранение заметки

Для сохранения заметки нам нужно выбрать соответствующий пункт в меню. Создайте файл res/menu/note.xml:

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

Опять же, я не стал приводить код удаления и вывода информации о заметке. При просмотре исходного кода, вы можете заметить, что помимо идентификатора заметки я передал в NoteActivity позицию заметки в списке. Это нужно для того, чтобы при удалении заметки на экране просмотра заметки, она также удалялась из списка. Для реализации этого функционала я использовал EventBus. И опять, я не стал приводить код.

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

Благодарности

Конечно же, нельзя забывать о людях, которые помогли мне при написании статьи. Хотел бы выразить благодарность хабраюзерам Юрию Шмакову (@senneco) за помощь с его библиотекой Moxy и за помощь по другим вопросам. Также, хочу сказать спаcибо сотруднику JetBrains Роману Белову (@belovrv) за ревью статьи и за предоставленный код на Anko.

UPD: Еще хотел сказать спасибо Sirikid за EPIC COMMIT, благодаря которому я переделал внушительную часть кода с использованием фич Kotlin’а.

Заключение

Надеюсь, эта статья смогла убедить вас в том, что писать приложения на Kotlin не трудно, а может даже и легче, чем на Java. Конечно же, могут встречаться и баги, которые сотрудники JetBrains достаточно быстро фиксят. Если у вас появились какие-либо вопросы, вы можете задать их напрямую разработчикам на Slack-канале. Также вы можете почитать статьи о разработке на Kotlin здесь.

Источник

LibGDX + Scene2d (программируем на Kotlin). Часть 0

И снова всем привет! Спешу поделиться, у меня были отличные выходные! Полтора дня я обдумывал вариант подачи материала, пилил макет и вообще всячески старался сделать хорошо. Что такое хорошо в контексте обучающего материала? На мой взгляд это «интересность», краткость, корректность и наглядность. Для меня лично написать такую статью — это подвиг. А вот серию статей — просто емкая и ответственная задача. Изучать Scene2d мы будем в процессе написания игры с нуля! Процесс нашего творчества растянется на долгие десять-двенадцать дней. Мне хочется верить что периодичность материалов будет примерно раз в день. Для меня лично это очень амбициозная задача, ведь требуется не столько запрограммировать, но и описать в статьях с детальным разбором. Я не сторонник бросаться в бушующий океан, в надежде научиться плавать. Мы прыгнем у лужу и будем последовательно ее углублять и расширять. Итак начинаем.

Разработку любой программы я настоятельно советую начинать с составления карточки продукта. Из обязательного — цели. Я составляю карточку продукта в Google Docs и вот как карточка выглядит в нашем случае.

Средневековый магнат

Цели проекта

  1. Демонстрация процесса разработки игры для сайта habrahabr.ru (общественная, информационная, краткосрочная)
  2. Создание материалов, которые впоследствие могут быть использованы как обучающие (личная, репутация, долгосрочная; общественная, информационная, долгосрочная)
  3. Создание основы для коммерческой игры (личная, краткосрочная)
  4. Привлечение скачиваний из Google Play (личная, финансовая, долгосрочная)

Первым делом стараемся максимально честно разобраться со своей мотивацией. Зачем мы вообще влезаем в это дело. Что будет служить нам путеводной звездой когда все хорошо и пинком под зад когда все плохо. Пожалуйста постарайтесь избегать альтруизма и “мира во всем мире”. Человеческая психика устроена таким образом, что личные побудительные мотивы значат больше чем общественные (визионерскую психологию тут не рассматриваю).

Игровой мир

Средние века / фэнтези
Цель игры — много денег
Сбор ресурсов
Продажа

Описание процесса игры

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

Игрок собирает ресурсы и продает их на местном рынке. На поиск и сбор ресурсов тратится еда/энергия. Когда энергия кончилась, ее необходимо покупать в городе.

Прототип интерфейса

Несмотря на то, что в предыдущей статье я рекомендовал тетрадку и карандаш в качестве инструментов для прототипирования, этот макет сделан в Adobe Experience Design CC (Beta). На момент публикации статьи, его можно скачать бесплатно. На работу с ним я угрохал полтора дня но считаю это оправданным. Дело в том, что публикация на Хабре является групповой работой, даже если я все делаю один. Чем более качественные опорные материалы я предоставлю, тем легче будет воспринимать информацию. Вот проектный файл Adobe Experience Design. Его можно скачать, запустить в режиме презентации и даже немного потыкать по кнопкам. Технически можно запилить отдельную статейку, но не знаю нужно ли это. Комментарии рассудят.

Ну и какая разработка без публичного репозитория? Вот ссылка.

Для работы нам понадобится Android Studio 3.0 (на данный момент доступна версия Canary 5), Android SKD и LibGDX. Установку всех этих тряхомудрий я пропущу, тут все большие мальчики и девочки. На крайний случай есть комментарии.

Запуск мастера конфигурирования LibGDX происходит из командной строки:

Кто был не в курсе, LibGDX это кроссплатформенный фреймворк, позволяющий писать одновременно под PC, Android, iOS и даже HTML (для последнего используется GWT, а у нас Kotlin, так что HTML нам точно не грозит). Из расширений я выбрал два:

Freetype — позволяет генерировать растровые шрифты из ttf/otf
Tools — среди прочего позволяет генерировать атласы текстур

Коммит с получившимся проектом доступен в репозитории. Я старался крошить и именовать коммиты таким образом, чтобы было просто понять какой фрагмент за что отвечает. Так как LibGDX кроссплатформенный, я предпочитаю большую часть разработки проводить на PC и тестировать/исправлять ошибки под Android непосредственно перед релизом. Как правило на эту работу уходит не больше 2-3 часов времени.

Дальше в этой статье

Запуск проекта через DesktopLauncher

Обратите внимание, что рабочая папка для DesktopLauncher расположена в android/assets. Запуск DesktopLauncher на коммите:

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

Обратите внимание, что даже только что сконфигурированный проект не запускается под android. Мы поправим это на следующем шаге.

Перевод проекта на Kotlin

LibGDX проекты сконфигурированы как мультимодульный gradle. Есть проектный build.gradle и модульные build.gradle для core, android и desktop. Почти весь код мы будем писать в core. В проекте android позже у нас будет сидеть AdMob + конфигурация immersive mode + покупки в Google Play маркете.

Для перевода проекта из java в kotlin мы меняем все apply plugin: «java» на apply plugin: «kotlin». В android/build.gradle добавляем apply plugin: ‘kotlin-android’. Самые большие изменения произошли в проектном build.gradle

Добавился гугловый репозиторий, в buildscript.dependencies добавлен kotlin-gradle-plugin и в core проект добавлена compile-зависимость kotlin-stdlib (в нашем случае kotlin-stdlib-jre8).

Данная версия работает на android, но не работает в desktop варианте из-за ошибки Android Studio 3.0 Canary 5. Почему я считаю что это причина — запуск gradle цели desktop-run таки запускает приложение (правда требует запущенное Android device/emulator для запуска android:run). А вот запуск из Android Studio выкидывает Exception in thread «main» java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics. Если кто сможет победить запуск DesktopLauncher’a со свежей версией gradle — дайте знать пожалуйста!

Перевод java файлов в kt элементарна — выделяете файл/папку и жмете Ctrl+Alt+Shitf+K. Единственная ошибка которая возникнет у вас после данной операции заключается в требовании Kotlin’a инициализировать свойство в момент определения:

internal = package видимость в java. Нам пакетная видимость не нужна (и вообще через пару коммитов мы удалим эти поля). Не во всех случаях мы можем проинициализировать поле сразу, а делать его nullable это вообще глупость (нам котлин интересен как раз из-за null-safety). Для этого в kotlin есть модификатор lateinit, который говорит компилятору, что программист зуб дает, на момент использования этого поля оно не будет равно null. Это так называемая синтаксическая соль. Вообще, если смотреть на этот код не как результат автоматической конверсии, то уместнее бы смотрелось:

Ошибка Kotlin not configured

Эту ошибку вы будете видеть каждый раз при запуске Android Studio. Просто щелкните синхронизировать gradle:

Конфигурация gradle для kotlin-desktop версии

Как я уже говорил, я предпочитаю разрабатывать desktop версию приложения, и изменением пары строчек мы реанимируем этот режим. Все что нужно — указать в проектном build.gradle
classpath ‘com.android.tools.build:gradle:2.3.2’, а в gradle-wrapper.properties версию gradle-3.3-all.zip

Конфигурация портретной ориентации для desktop версии

В DesktopLauncher добавляем горсть параметров конфигурации. Три относятся к размеру окна и возможности изменения размеров. Четвертый параметр vSync отключен т.к. есть глюк, на некоторых видеокартах в desktop и только на config.foregroundFPS=60 (по умолчанию), грузит одно ядро процессора в 100%.

Первое использование Scene2D. Загрузочный экран, загрузочная сцена

Вот мы и добрались до первого использования Scene2D. Коротко пару слов для чего он предназначен и что можно от него хотеть.

Scene2D является графом (деревом) элементов и предназначен в первую очередь для создания UI. Прямо «из коробки», вы получаете возможность верстки, трансформации элементов (поворот, масштаб, сдвиг и т.д.). Огромным плюсом идет обработка касаний. Ну и вишенка на торте система действий. С непонятным определением закончили, теперь то же самое человеческим языком.

Есть сцена, она занимает весь экран. На сцене вы можете разместить таблицу, в таблице картинку, панель прокрутки, десяток кнопок и даже черта лысого (главное чтобы в душе он был Actor’ом). При помощи волшебных слов top/center/left/width и т.д. вы реализуете верстку. Пример сложнее чем hello world будет только завтра, и так статья большая получилась. Дальше на любой произвольный элемент вы вешаете обработчик касания и он работает. Вам не нужно вручную ловить координаты клика, проверять что же находится там, какой у объектов z-index и т.п. Но еще раз, про это завтра. А сегодня просто несколько фрагментов кода напоследок:

Наш класс MedievalTycoonGame теперь наследуется от Game, вся задача которого свалить работу на Screen. Первый экран, который мы сейчас покажем пользователю будет называться LoadingScreen и будет содержать одну сцену — LoadingStage. Т.к. не предполагается разрастания этих классов, я размещу их в одном файле LoadingScreen.kt

Все что делает LoadingScreen — затирает экран черным цветом и вызывает методы act() и draw() у LoadingStage. На act() очень удобно вешать логику программы, работу с данными. Draw() это просто отрисовка всех элементов сцены.

Единственный момент, хочу заакцентировать как выглядит инициализация сцены java vs kotlin

В случае с kotlin у нас всегда инициализация элемента и его размещение на соседних строчках. Это достигается за счет функции расширения apply. Иерархия в kotlin автоматически создает отступы и визуально очень легко читается. В java вся верстка идет без отступов. Инициализация элемента и его размещение часто невозможно рядом. Если иерархия состоит из 3+ уровней глубины, упорядочить элементы красиво (и дешево в поддержке) в java невозможно.

На сегодня это все. Рассматривайте эту статью как вводную, собственно раскрытие Scene2D и реализация игры будет завтра и далее. Спасибо что были с нами 😉 И не рекламы ради (в этом приложении надо приложить усилия чтобы увидеть рекламу), мой первый проект «Пятнашки» на Scene2D когда я еще только-только осваивал. Из достоинств — удобство управления. Существуют сотни если не тысячи версий приложения и в 90% что я видел передвижение фишек возможно только тычком в соседнюю с пустой клеткой. Попробуйте собрать котика.

В следующих статьях

  • Базовые элементы Scene2D
  • Два базовых контейнера для верстки
  • Атлас текстур
  • Шкурки
  • Интернационализация

P.S. В загрузочном экране использована работа художника Виталия Самарина aka Vitaly S Alexius.

Upd:
ссылка на исходники Пятнашек

Источник

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