Это не инструкция как сделать. И не попытка преподать урок. Это больше похоже на тайминг процесса изготовления продукта, в нашем случае простого приложения и размещения его в магазине Google Play.
Это статья не совсем подойдет для тех, кто учится на программистов, чтобы пройти собеседование и устроиться на высокооплачиваемую работу. И не для специалистов - они не почерпнут для себя много нового.
Это статья для тех, у кого есть идея простого (по настоящему) приложения и нужно понять реальные временные рамки изготовления работающего продукта. Для тех, для кого писать программы под Андроид хобби. Для тех, кому просто интересно, а как это выглядит с той стороны. А еще для таких как я - 39 лет. Занялся Андроид разработкой в конце 2018 года. До этого работа никак не связанная с IT. Но за плечами профильная и давняя вышка.
Новичкам. Это статья просто окунает в процесс разработки. Вам может быть ничего не понятно и это нормально.
Иллюстрации могут повергнуть вас в шок. От программиста таких вы не ожидали. Это фотографии экрана.
Начнем.
Каждый день в Google Play появляется 60 тысяч новых приложений. Сложно придумать такое, какого еще нет, и которое несло бы ценность для пользователя. Сложно, но можно.
У заказчика была только идея. А идея заключалась в том, что он не смог найти такое приложение таймера, которое где-то просто сохраняло бы измерения времени какого-то процесса (езды с работы домой или наоборот, как долго он сможет не дышать или сбегать в магазин) и к ним можно было бы вернуться.
Забегая вперед, скажу что, я, оказывается, не знал точно в чем разница между таймером и секундомером. Это сыграет свою роль в истории.
С чего начинается создание приложения у меня?
Иконка приложения.
Это как стройка начинается с туалета. Не могу смотреть на стандартную андроид иконку. Любую другую, найти или самому нарисовать.
Иконка называется launcher.
Здесь AdobeXD (1) и (3) - бесплатный софт от Adobe для рисования.
Интернет (2) - поиск иконок (в векторном формате)
Android Studio (4) - то место где пишется приложение - среда разработки.
Экран эмулятора (5) - эмулятор Андроид с установленным приложением и с иконкой.
Создать экран. Снизу таймер. Сверху список.
Android Studio - это специальная программа от Google для разработки Андроид приложений. Скачивается и устанавливается совершенно свободно.
В Android Studio создаем макет (layout) главного экрана нашего приложения. Макеты - это важный элемент в программировании приложений для мобильных устройств. Макет определяет набор элементов и их местоположение и на экране устройств. Макеты в Android Studio могут быть сразу визуализированы для удобства разработчиков, но изначально это текстовые файлы написанные в XML формате.
Создать стрелки и запустить их анимацию.
Adobe XD(1) и Android Studio (2)
Изображение секундомера будет формироваться из трех картинок - фоновое изображение и стрелки: секундная и минутная. Анимация реализуется простым поворотом изображений минутной и секундной стрелки на высчитываемый в зависимости от разности текущего времени и времени старта угол. Пересчет и перерисовка происходят каждые 30 миллисекунд для плавности движения секундной стрелки.
Создать класс записи и сохранение базы записей.
процесс написания собственно приложения пошёл.
на самом деле здесь ничего страшного нет.
Например, TimerNote это я так назвал класс который описывает конкретную запись Таймера. У которой есть время старта, время стопа и дополнительные параметры - название и комментарий. А храниться объекты записей будут в классе DataBase реализованным по паттерну "Одиночка - Singleton" т.е. объект класса будет один и только один. Данные из DataBase при изменении сохраняем в файлы, а при старте приложения считываем их из фалов и наполняем DataBase. Пока у нас один файл со списком записей.
У нас есть список записей и его нужно показывать.
Наш экран мы разделили ранее на две части. В нижней части у нас изображение часов. Если по нему кликнуть, то сохраняется в памяти метка текущего времени - время старта. В приложении устанавливается флажок о том, что оно в процессе работы таймера. И следующий клик по часам уведомляет о том, что это стоп и также сохраняется время клика. Из пары стартового времени и стопового делается запись. Ее мы добавляем и показываем вместе с предыдущими в верхней части экрана. Вывод списка организован на RecyclerView - практически стандарт представления любых списочных данных на Android.
Нахождение нормальной функции перевода штампа времени в текстовую строку.
Штамп времени (TimeStamp) это целое число (формат long) выражающее текущее время в миллисекундах с 1 января 1970 года.
Выше штамп времени уже переводится в текстовый формат, но хочется показывать в привязке к текущему моменту и кратко. Не 29.11.2020 15:38:40, а просто 44m назад. Продолжительность не 00:00:07, а 7s. Нашел что подобное на GitHub. В будущем эту функцию буду переписывать, она как элемент дизайна, ничего сложного, но нужно долго вертеть , чтобы привести в должный вид. Сейчас не стоит убивать много времени на нее.
Сделать так, чтобы новые записи отображались вверху списка.
На этот момент - самый основной функционал реализован. Всего потрачено времени 6 часов 36 минут и 26 секунд.
Запускаемый файл apk отправлен заказчику. Пусть запустит и убедится, что приложение выполняет его требования.
С этого момента начинается основная работа по приведению приложения в должный вид, его доработке и наполнению дополнительным функционалом.
И самое первое что попросил заказчик - сделать так, чтобы новые записи отображались вверху списка. Это не сложно.
Конечно нужно позволить пользователю удалять ненужные записи. Вопрос как? Чтобы самому себе не сделать ненужной работы в будущем по переписыванию функционала - лучше сразу придумать хороший способ. Мне показалось что свайпом в сторону удалять записи лучше всего. Свайп для удаления это практически стандарт в UX (User Experience - Пользовательском взаимодействии).
Цифровой таймер.
Это вполне себе правильное пожелание заказчика. Логично сделать рядом с циферблатом.
Меняем цифры в той же функции где перерисовываются стрелки. С точки зрения “чистоты кода” это не совсем правильно, но вот по методике KISS - keep it simple stupid - нормально.
Добавим.
Редактирование заголовка и комментария записи.
Фишка нашего таймера как раз и заключается в том, что записи измерений можно именовать и подписывать? Надо сделать.
Кто то внимательный спросит, а почему так долго то - пять часов? Нужно вид записи разделить надвое. Раскрывать и закрывать. В раскрытом состоянии показать поля ввода. Читать ввод и сохранять в базе контролируя позицию. А до этого прокрутить в голове несколько вариантов реализации функционала - может вообще отдельное окно надо показывать пользователю с вводом или еще как…
Первый день разработки закончен.
При старте секундомера - увеличивать его (второй день разработки).
Невозможно знать все и приходится постоянно что-то изучать. Так и при этой подзадаче. Можно было пойти по протоптанной тропинке и просто в коде увеличить изображение секундомера. Переместить цифры. И все это контролировать в коде. Но в будущем при малейшем изменении вида - нужно лезть в код и вручную исправлять цифры. Надо найти другой способ. Сейчас потратить больше времени на изучение, но в будущем это знание сэкономит кучу времени. Найдено простое и эффективное решение - разделить один экран на два вида. Был один layout, стало два. Теперь в коде можно просто переключать виды экрана и даже с плюшкой в виде анимации элементов.
Перерисовать секундомер.
Это и пожелание заказчика и мое. Получилось так.
Перемещать записи по разделам (папкам).
Сейчас все записи хранятся в одном списке. Хорошо бы дать возможность пользователю разделять их. Делаю псевдо файловую систему. По факту одна папка отвечает за один файл в котором хранятся все записи. Ввел еще один экран (новый класс activity назвал DirectoryActivity) где можно работать с папками, создавать их и просматривать содержимое. С главного экрана свайпом теперь можно не только удалять записи, но и переносить их в папки.
Папка по умолчанию (Третий день разработки).
Если у пользователя нет никаких папок, то надо ему предложить ее создать или создать за него по умолчанию. Создаем по умолчанию и называем "Новая папка".
Перечитывать список папок при возврате на главный экран.
Список папок организован через HashMap<String, String> ключ (случайный, имя файла) и сам HashMap сохраняется в отдельный файл. Под капотом программы много мелочей, которые нужно учитывать. Так, например, главный экран (главная activity) не знал о том, что на экране папок создана новая. Это надо исправить.
Визуализация записи в папку.
Желательно сделать так, чтобы визуально пользователю было понятно что происходит с его записью на главном экране. Итак, свайп влево это удаления. Свайп вправо перемещение в папку, которую должен выбрать пользователь. И если папка не выбрана - то оставить запись на главном экране. В главном списке.
Удаление папок.
Давно хотел разобраться с Drag'n'drop в списках RecyclerView и разобрался. Удаляем папки перетаскиванием в корзину. Корзина появляется в момент перетаскивания.
Запрет редактирования записи на главном экране во время запущенного таймера.
Вот видите. Редактировать нельзя. Это, конечно, шутка. Через изображение сложно подобное передать.
Информационная строка на экране с папками.
Удаление записей на экране папок или перемещение записи назад в общую папку.
Продолжать работу секундомера в фоне. (Четвертый день разработки)
В настройки приложения, организованные через SharedPreferences, закидывается состояние таймера. При открытии оно читается и таймер восстанавливается.
Важная опция. Никому не нужен таймер, который при малейшем чихе сбрасывает свое состояние.
В будущем фоновая работа будет дополнена сервисом уведомления. А пока это конечно, квази фоновая работа. Попутно добавил бегущие сотые доли секунд.
Возможность работы с сохраненными в папках записями во время работы секундомера.
Когда разделял главный экран на два вида (секундомер не запущен/ секундомер запущен), я просто копировал главный вид и модифицировал его. Теперь если добавляются новые элементы, то нужно не забывать их дублировать на второй экран, если они нужны на втором экране. Так - иконку папки, по которой мы переходим в экран где хранятся отсортированные записи, нужно продублировать на второй экран главной активности (activity) и во время работы секундомера можно просматривать старые записи.
А как же без багов? Конечно они есть у меня.
При добавлении новой папки, она рисовалась в случайном порядке с иконкой корзины. Это связано со спецификой организации списков выбранной мной. Исправил.
Видите на картинке нет ни одной иконки корзины. Значит, действительно, исправил. Это тоже шутка. Фотографии с глюком не сохранилось.
Больше информации в раскрытой для редактирования записи.
Это просит заказчик. Конечно можно.
Чтобы визуально разделить открытую и закрытую записи - разделил их цветом. Возможность по тапу пальцем на запись раскрывать или закрывать ее реализована еще в первый день.
Создаем окно диалога для подтверждения удаления.
При удалении папки с записями приложение не просит подтверждения!
Новый экран - Настройки. (Пятый день разработки)
Настройки нужны в том числе для того, чтобы пользователи могли выбирать разные темы оформления.
Здесь пришлось подтянуть знания и изучить стили, темы и работу с ними. Раньше соприкасался с ними по минимуму. Основное время заняло изучение. На иллюстрации вы видите только новый экран и три кнопки. А под капотом боль (извините) десятков тысяч Андроид разработчиков.
Оформить три темы. Подработать по ним дизайн.
Разделил темы так, что под каждую свои изображения часов и набор цветов. Работа заключается в рисуй, переноси в Android Studio и привязывай не запутавшись к стилям.
Заказчик захотел свою тему. (Шестой день разработки)
Вводим тему заказчика.
Продолжение работы со стилями. Масса мелких недочетов убрана. Введена возможность заранее задать название записи и комментарий к ней. Поправлены иконки папок. В целом по дизайну работа.
Убрать всплывания клавиатуры и фокуса на поле редактирования. (Седьмой день разработки)
Разработчиков в гугл рекрутируют из благотворительных организаций. Они готовы помочь всегда и везде. Приходится запрещать особенно навязчивые помогающие функции. Одна из таких - всплывание системной клавиатуры при обнаружении на экране поля в котором можно что то ввести. Убираем принудительно и костыльно. Создаем нулевое поле на которое будет фокусироваться система. Лучше решения пока не придумал и не нашел. Так выглядит текстовый файл разметки экрана в формате XML. Как китайская клинопись для меня, когда я начинал.
Затухание экрана. предоставить выбор в настройках.
Ну это безусловно необходимая функция для приложения такого типа. И, конечно, пусть пользователь сам решает надо его спрашивать или не надо об удалении записи. Фото не сохранилось.
Визуальное представление. Немного UI
А как насчет того чтобы пользователь мог охватить взглядом сразу много записей для анализа? Может какое то графическое представление?
Нужная вещь. Делаем. Используем стандартный линейный ProgressBar для отображения величины графика. В коде анализируем список записей, в котором ищем самую долгую и устанавливаем ее значение как максимальное для всех.
Работа с мелочами.
Программа разрастается. Нужно ее повертеть по всякому и поработать с шерховатостями. В основном по представлению записей.
еще картинка
Сворачивание содержимого по нажатию на папку сверху. Перезапуск таймера (Восьмой день разработки)
Убрал курсор при развороте записи на главном экране.
Старт таймера через свайп вправо старой записи. Пришла интересная мысль сделать перезапуск старой записи с теми же заголовком и комментарием. Делаю.
А не поменять ли иконку приложения?
С чего начинали тем и завершаем. )
Сейчас иконка такая как справа. Первоначально выкладывалась в Google Play левая версия. Когда вы читаете статью, возможно будет уже иная картинка.
Инструкция по пользованию.
Рисуем ее в настройках.
Волнительный момент - загрузка в Google Play.
Во все страны и континенты. На все устройства. Для всех возрастов. Не ну а что?
Гугл будет проверять приложение какое то время. Обычно до недели.
А теперь приступаем к разработке таймера (Девятый день разработки).
При размещении в Google Play я подзавис на названии и описании. Как назвать приложение? Таймер блокнот или еще как. И вот в это момент закралось какое-то подозрение в голову. Лег спать. Проснулся. И для убеждения в том, как же знатно я опростоволосился с названием, а значит и с перспективой выдачи в топе поиска загуглил.
Для тех кто так же как я не придавал значения разнице между таймером и секундомером -
Таймер считает в обратную сторону до момента события. Секундомер измеряет продолжительность события/процесса. И даже термины на английском для них разные - Timer и StopWatch.
Ну что ж. Буду реализовывать то о чем уже заявил. Я то ведь до этого момента сделал StopWatch.
Возможно если бы не эта ошибка, то я и не стал бы делать именно Таймер. А так приложение получилось интересной своей особенностью сочетания таймера и секундомера.
Пользователь может провести измерение процесса секундомером и по этому измерению запустить таймер.
Жду публикации в гугл. Когда приложение будет одобрено сразу буду заливать обновление с Таймером.
Сделаю свою вью часов (Десятый день разработки).
Вью - это такой особенный класс у разработчиков мобильных приложений. Например, есть TextView для отрисовки текста на экране со своими параметрами типа высоты, шрифта, цвета и т.д. ImageView - для отрисовки изображений. А я сделаю свой ClockView, для отображения часов. Ему мы будем передавать три картинки - фон и две стрелки. И параметры в времени начального времени и конечного. Эта вью нам возможно очень пригодится в будущем при развитии Таймера.
Про спортсменов.
Главная идея секундомера заключалась в том, чтобы сохранять и систематизировать записи об измерениях. Но мы совсем “забыли” о самых главных потребителях секундомеров. О спортсменах. Ну хорошо. Вот флажки. Тут и вью из предыдущего шага пригодилась.
Надо добавить флажки (у спортсменов обычно именуют кругами) в просмотр у записи. (Одиннадцатый день разработки)
10 декабря приложение было одобрено и появилось Google Play. Которое я сразу же обновил на последнюю версию с таймером.
Теперь дальнейшая судьба его будет зависеть от интереса к нему со стороны пользователей.
Многие будут считать, что оно совершенно ненужно и подобных тысячи. Сразу скажу, подобных не тысячи. Если бы подобных было много, я и мой заказчик (по совместительству брат) не стали бы браться за это дело. Инвестиции в приложение со стороны заказчика - 10000 рублей на поддержание штанов.
Проект будет развиваться - в нем обязательно нужны фичи мультитаймера, восстановления в случае случайного стопа, уведомления звуковые и визуальные, выгрузка данных, расшаривание и много чего еще - новых тем можно добавить и дизайн дорабатывать.
-Я тренируюсь игре на духовых инструментах, мне нужно знать свой прогресс. Как долго я играю разные ноты. Я же могу по разным папкам разные замеры делать и потом видеть прогресс?
Такой вопрос мне задали недавно.
Отвечаю: Да. Именно для подобных измерений этот таймер секундомер и сделан.
СПАСИБО!
ps. Почему фотографии экрана? А это у меня есть другое приложение, которое я разрабатываю. В нем я задаю себе задачу и делаю старт. А когда задача завершена, делаю стоп и обязан сфотографировать результат, иначе не пропустит дальше. Вот так я и протоколировал создание уже этого приложения. Поэтому фотографии. Но зато в динамике)