Вы находитесь на странице: 1из 43

Министерство науки и высшего образования Российской Федерации

НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ
ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ (НИ ТГУ)
Научно-образовательный центр «Высшая ИТ школа»

КУРСОВАЯ РАБОТА

Разработка функционала для работы с садками в Android-приложении для хранения


и мониторинга параметров процесса технологической обработки изделия.

Бабак Виктория Михайловна

Руководитель
ассистент кафедры
программной инженерии
______________Л.С. Иванова

«_____»____________2022 г.

Выполнил
студент группы 971902
______________В.М. Бабак

Томск - 2022
РЕФЕРАТ

Курсовая работа 42 страницы, 25 рисунков, 14 листингов, 3 таблицы, 16


источников.
МОБИЛЬНОЕ ПРИЛОЖЕНИЕ, ANDROID, MVVM.

Объект разработки: мобильное приложение для мониторинга, хранения и анализа


параметров процесса технологической обработки изделия.

Цель работы: разработать функционал для мониторинга и хранения параметров


процесса технологической обработки изделий для платформы Android.

Результат работы: спроектирован и разработан новый функционал для мобильного


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

2
ОГЛАВЛЕНИЕ

Глоссарий............................................................................................................................4

Введение.............................................................................................................................5

1 Анализ требований.........................................................................................................6

1.1 Анализ текущего состояния объекта.....................................................................6

1.2 Функциональные требования.................................................................................8

1.3 Нефункциональные требования...........................................................................13

1.4 Модель предметной области.................................................................................14

2 Анализ инструментов и выбор архитектуры приложения........................................15

2.1 Выбор инструментов разработки.........................................................................15

2.2 Архитектура Clean Architecture............................................................................16

2.3 Архитектура MVVM..............................................................................................17

2.4 Шаблон наблюдателя – MVVM + LiveData........................................................18

2.5 Пакеты приложения...............................................................................................19

3 Реализация.....................................................................................................................20

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

3.2 Взаимодействие с сервером..................................................................................21

3.3 Хранение данных...................................................................................................23

3.4 Навигация...............................................................................................................24

3.5 Боковое меню.........................................................................................................26

3.6 Календарь...............................................................................................................28

3.7 Добавление фотографий........................................................................................30

3.8 Списки.....................................................................................................................31

3.9 Отправка событий между несвязанными классами............................................32

3.10 Реактивное программирование...........................................................................33

Заключение.......................................................................................................................35

Список использованных источников литературы........................................................36

Приложение A..................................................................................................................38
3
ГЛОССАРИЙ

ТП — технологический процесс термообработки изделий.


Садка — приспособление, используемое для укладки металлических изделий и
прохождения термообработки данными изделиями.
Журнал ТП — список садок, находящихся в процессе термообработки.
Номенклатура — перечень параметров, указывающих на вид изделия.
Партия — перечень изделий, сформированный из одной или нескольких
номенклатур.
Activity — один отдельный экран в Android, который позволяет размещать
различные компоненты пользовательского интерфейса или виджеты на данном экране.
Activity имеет свой собственный жизненный цикл: оно может находится в различных
состояниях в зависимости от активности приложения.
Фрагмент — Часть визуального интерфейса приложения, который возможно
использовать многократно. У фрагмента есть свой жизненный цикл и свои обработчики
для различных событий. Несколько фрагментов возможно одновременно отображать в
одной Activity.

4
ВВЕДЕНИЕ

В настоящее время использование мобильных приложений стало частью


повседневной жизни практически каждого человека. И это неудивительно, ведь на
прогулках, во время поездок и командировок, люди желают иметь всегда под рукой
инструмент, удобный и необходимый для приятного времяпровождения, а также для
рабочих целей. Программы, созданные специалистами сферы мобильной разработки,
позволяют повсеместно осуществлять соединение с интернетом, составлять нужные
маршруты на карте, оказывать помощь в поиске специалистов или необходимых товаров.
Эти приложения дали возможность экономить такой ценный ресурс, как время человека.
Мобильные приложения очень полезны компаниям и корпорациям для
автоматизации бизнес-процессов, быстрого получения отчетов, отслеживания различных
важных показателей и упрощения взаимодействия с клиентами. Они имеют огромный
охват аудитории – около 67% населения мира пользуются смартфонами, а в России
статистика показывает, что мобильными устройствами владеют 98% населения.
Приложения дают возможность постоянно находиться на связи с пользователями, а также
получать от них обратную связь.
У компании-заказчика появилась необходимость улучшения продуктивности
рабочего процесса. Заказчик хотел автоматизировать мониторинг и хранение параметров
процесса технологической обработки изделий. Для удовлетворения этой потребности,
было принято решение о разработке мобильного приложения для работников завода.
Чтобы разработать функционал для мониторинга и хранения параметров процесса
технологической обработки изделий, были сформулированы следующие задачи:
проанализировать требования заказчика, спроектировать архитектуру и непосредственно
реализовать приложение.

5
1 Анализ требований

Перед началом разработки нового приложения, необходимо провести анализ


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

1.1 Анализ текущего состояния объекта

В настоящее время процесс термической обработки осуществляется в соответствии


со следующим алгоритмом действий:
1. Принять детали, зафиксировать количество принятых в журнале.
2. Проверить внешним осмотром вид деталей - 100% деталей. При выявлении
несоответствий детали предъявить в ОТК.
3. Собрать приспособление на столе загрузки вручную.
4. Взять деталь из тары и уложить на приспособление вручную.
5. Установить приспособление с деталями на транспортную тележку и перевезти к
печи нагрева.
6. Зафиксировать в журнале количество деталей и номенклатуру.
7. Загрузить приспособление с деталями в печь нагрева при помощи загрузчика
тележки.
8. Нагреть детали в печи нагрева.
9. Выдержать детали в печи нагрева.
10. Закалить детали в закалочном баке.
11. Выдержать детали в предкамере печи нагрева для стекания масла.
12. Выгрузить загрузчиком тележки приспособление с деталями из печи нагрева и
перевезти на транспортной тележке к моечной машине.
13. Загрузить загрузчиком тележки приспособление с деталями в зону промывки.
14. Промыть детали в камере промывки моечной машины.
15. Выгрузить загрузчиком тележки приспособление с деталями из моечной
машины и перевезти на транспортной тележке к печи отпуска.
16. Взять детали из разных мест садки и предъявить в ОТК для проверки твердости
– не менее 5-7 деталей от садки.

6
17. Внести в журнал информацию о температурах, используемых при обработке.
Количество принятых изделий, а также отправку в лабораторию.

В журнале также фиксируется дата, смена, ФИО термиста, время прохождения


этапов термообработки. Примеры бумажного формуляра представлены на рисунке 1.1.

Рисунок 1.1 – Журнал термической обработки деталей

Мониторинг с помощью бумажного журнала, приведенного выше процесса


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

7
1.2 Функциональные требования

Компания-заказчик предоставила требования к мобильному приложению. Они


проиллюстрированы на рисунках 1.2, 1.3 и 1.4. Варианты использования были разбиты на
отдельные диаграммы для улучшения читаемости.
Одним из основных требований было разделение пользователей приложения по
ролям. Пользователями системы являются:
1. Термисты - сотрудники, непосредственно выполняющие термообработку
изделий.
2. Сотрудники ОТК - сотрудники, осуществляющие контроль качества
термообработки изделий.
Набор предоставляемых пользователю прав на выполнение функций зависит от его
роли (Таблица 1.1)

Таблица 1.1 – Список функций пользователей по ролям

Роль Доступные функции

Термист  просмотр журнала ТП;


 создание записи в журнале ТП;
 редактирование записи журнала ТП;
 запуск этапа ТП;
 просмотр детальных сведений о ТП выбранной садки в
журнале ТП;
 остановка/возобновление ТП обработки изделий.

Сотрудник  просмотр журнала ТП;


ОТК  просмотр детальных сведений о ТП выбранной садки в
журнале ТП;
 контроль качества термообработки изделий.

Одним из основных процессов в работе приложении является просмотр журнала


ТП. Ниже расположена диаграмма вариантов использования для этого процесса от лица
термиста (Рисунок 1.2). Термист может создавать, редактировать и просматривать садку.
Сотрудник ОТК обладает меньшей функциональностью при взаимодействии с журналом,
например, он не может создавать и редактировать садку. Сотрудник ОТК может
осуществлять перевод садки на некоторые дополнительные этапы (Рисунок 1.3).

8
Рисунок 1.2 – Просмотр журнала ТП для термиста

Рисунок 1.3 – Просмотр журнала ТП для сотрудника ОТК

При создании садки (рисунок 1.4), пользователь должен добавить в нее как
минимум одну номенклатуру и фотографию. Уже созданную номенклатуру можно
редактировать или удалить. Фотографию можно только удалить. Для сохранения
номенклатуры пользователю необходимо выбрать партию из списка, а при наличии
бракованных деталей становится обязательным указание контролера.

9
Рисунок 1.4 – Добавление, редактирование и удаление номенклатуры в садке

Одним из наиболее сложных и важных процессов в работе приложения является


редактирование существующей садки. В таблице 1.1 приведен сценарий варианта
использования «Редактировать садку».

Таблица 1.1 – Сценарий варианта использования «Редактировать садку»


Пользователь Приложение
Предусловие
Пользователь находится на экране редактирования конкретной садки
Основной сценарий
1. Нажимает кнопку «Добавить
номенклатуру»
2. Отображает экран создания
номенклатуры садки
3. Нажимает на поле «Партия»
4. Отправляет запрос на получение списка

10
партий
5. Отображает экран со списком партий
6. Выбирает партию
7. Передает выбранную партию на экран
создания номенклатуры
8. Отображает экран создания
номенклатуры
9. Вводит общее количество деталей
10. Нажимает кнопку «Сохранить»
11. Проверяет наличие выбранной партии
12. Проверяет, что общее количество
деталей больше нуля
13. Передает созданную номенклатуру на
экран создания садки
14. Отображает экран создания садки
15. Нажимает на кнопку добавления
фотографии
16. Отображает диалоговое окно с
выбором источника для добавления
фотографии
17. Выбирает добавить фотографию из
галереи
18. Открывает экран выбора фотографии
из галереи
19. Нажимает на фотографию
20. Передает фотографию на экран
создания садки
21. Открывает экран создания садки
22. Конвертирует фотографию в Base64
23. Нажимает кнопку «Сохранить»
24. Проверяет наличие хотя бы одной
фотографии и одной номенклатуры
25. Проверяет, что количество фотографий
не более 5

11
26. Отправляет садку на сервер
27. Отображает результат сохранения
садки
Расширения
Расширение шага 9. Пользователь вводит общее количество деталей и количество
дефектных деталей, которое больше нуля
9. Нажимает на поле Контролер ОТК
9.1. Отправляет запрос на получение
списка контролеров
9.2. Открывает экран со списком
контролеров ОТК
9.3. Нажимает на контролера ОТК
9.4. Отправляет контролера ОТК на экран
создания номенклатуры
9.5. Отображает экран создания
номенклатуры
Расширение шага 12. Общее количество деталей не больше нуля
12.1 Отображает ошибку в поле общего
количества деталей
12.2 Вводит новое значение в поле общего
количества деталей
12.3 Нажимает кнопку «Сохранить»
12.4 Проверяет новое значение поля.
Расширение может повторяться до тех пор,
пока пользователь не введет корректные
данные
Альтернативы
Альтернатива 5. Пользователь хочет воспользоваться поиском партий
5.1 Пользователь вводит нужное слово в
поле для поиска
5.2 Отсылает запрос на сервер для
получения отсортированного списка
5.3 Отображает отсортированный список
партий

12
5.4 Выбирает партию
Сценарий продолжается с шага 7 основного сценария
Альтернатива 17. Пользователь выбирает сделать фотографию с помощью камеры
17.1 Открывает приложение для съемки,
установленное на телефоне пользователя
по умолчанию
17.2 Делает снимок
17.3 Передает фотографию на экран
создания садки
Сценарий продолжается с 21 шага основного сценария

Процесс технологической обработки садки тоже является одним из основных


процессов в МП. Технологическая обработка проходит в несколько этапов, которые
приведены на диаграмме состояний ТП садки (Рисунок А.12).
На каждом переходе на этап подписана роль пользователя, который имеет право
осуществлять данный переход, и условие, при котором он осуществляется.
Стоит заметить особенность процесса отправки садки на повторную обработку:
если в ходе этапа «Контроль отпуска» Сотрудник ОТК принял решение об отправке садки
на повторную обработку, он может, как и назначить полный цикл повторной обработки
(начиная с этапа «Закалка»), так и назначить повторение только этапа «Отпуск». После
отправки садки Контролером ОТК на повторную обработку садка переходит в статус
«Повторная обработка», и находится в данном статусе до тех пор, пока Термист не
возобновит ТП, отправив садку на повторную обработку заданных этапов.

1.3 Нефункциональные требования

При анализе были также зафиксированы некоторые нефункциональные


требования:
1. Приложение должно работать уже с существующим серверным RESTful API.
2. Весь текст в приложении должен быть на русском языке, помимо системных
ошибок.
3. Минимальная поддерживаемая операционная система – Android 5.1.
4. Дизайн приложения должен быть выполнен в соответствии с макетами,
разработанными дизайнером компании.

13
1.4 Модель предметной области

В результате анализа требований к приложению, описанных выше, была составлена


модель предметной области (рисунок 1.5).

Рисунок 1.5 – Модель предметной области

14
2 Анализ инструментов и выбор архитектуры приложения

2.1 Выбор инструментов разработки

Благодаря обилию сложных интегрированных сред разработки (IDE), процесс


создания приложения становится значительно быстрее и эффективнее. В список самых
популярных входит Android Studio [11], Eclipse [12], IntelliJ IDEA [13].
В данном проекте в качестве IDE была выбрана Android Studio. Вот ряд основных
плюсов данной среды:
1. Визуальный редактор макетов – при работе с XML-файлами макетов, Android
Studio предоставляет визуальный редактор с возможностью перетаскивания
элементов, который упрощает создание нового макета.
2. Быстрый и многофункциональный эмулятор, который устанавливает и
запускает приложения быстрее реального устройства, а также позволяет
тестировать приложения на различных конфигурациях устройств Android:
телефонах, планшетах, Android TV.
3. Интеллектуальный редактор кода, который предлагает возможности
автодополнения, помогающие писать более качественный код, а также работать
более быстро и продуктивно.
4. Гибкая система сборки
5. Удобство работы в команде – Android Studio интегрируется с инструментами
контроля версий, например такими как GitHub, что дает возможность
синхронизировать команду с изменениями проекта и сборки.
В качестве языка программирования был выбран Kotlin [15]. Kotlin – это
современный язык программирования со статической типизацией, который используют
более чем 60% профессиональных Android-разработчиков.
Основными преимуществами этого языка являются:
1. Лаконичность – современные языковые функции Kotlin позволяют
разработчикам сосредоточиться на выражении своих идей и писать меньше
стандартного кода.
2. Более безопасный код – с Nullable и NonNull, включенными в систему типов
языка, Kotlin помогает избежать исключений NullPointerException. Приложения
для Android, использующие Kotlin, имеют на 20% меньше шансов на сбой.
3. Интероперабельный – Kotlin на 100 % совместим с языком программирования
Java, поэтому Kotlin возможно использовать в проекте в любом количестве.

15
4. Структурированный параллелизм – сопрограммы Kotlin упрощают асинхронное
программирование, делая обычные задачи, такие как сетевые вызовы и
обновления базы данных, простыми и эффективными.
5. Приоритетность – в мае 2017 года компания Google опубликовала новость о
том, что инструменты языка Kotlin будут по умолчанию включены в Android
Studio, которая является официальным инструментом разработки OC Android. В
2019 году на Google I/O объявили, что Kotlin стал приоритетным языком
программирования в разработке под Android.

2.2 Архитектура Clean Architecture

Для организации классов и кода в проекте был выбран архитектурный подход –


Clean Architecture [16]. Плюсы выбора данного подхода:
1. Разделение ответственности – разделение кода на разные модули или разделы с
определенными обязанностями, что упрощает его обслуживание и дальнейшую
модификацию.
2. Слабое связывание – слабосвязанные модули легче разрабатывать и
поддерживать, поскольку они независимы друг от друга. Их разработка и
тестирование может идти параллельно.
3. Легкая тестируемость – возможность написания хороших тестов, ведь при
написании кода под многоуровневой архитектурой, логику можно тестировать
без пользовательского интерфейса, баз данных, сервера и других внешних
элементов.

Для реализации концепции «Чистой архитектуры» проект был разделен на четыре


отдельных модуля, каждый из которых ответственен за определенные задачи:
1) Presentation. Модуль взаимодействия с пользовательским интерфейсом. Здесь
размещены такие классы, как Activity, Fragment, ViewModel, функции
расширения и утилиты, которые участвуют в отображении данных на экране.
2) Domain. Модуль, содержащий в себе бизнес-логику приложения и классы
данных для работы с ней. Здесь размещены интерфейсы, связывающие другие
слои, а также реализации сценариев использования.
3) Data. Модуль, содержащий в себе классы для работы с сервером и локальным
хранилищем. Здесь находятся реализации классов и функций для
предоставления данных в Domain-слой.

16
4) App. Модуль, который является основной точкой входа в приложение, в нем
содержатся вспомогательные классы для внедрения зависимостей в проект.

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


пользовательском интерфейсе, об этом сообщается ViewModel в слое Presentation, чтобы
предпринять необходимые действия. Затем ViewModel подключается к юзкейсу(описание
некого атомарного действия), чтобы получить от него результат действия.
Юзкейс взаимодействует с классом репозитория, чтобы получить результат из
соответствующего источника данных (сеть или база данных).

2.3 Архитектура MVVM

Наряду с «чистой архитектурой» в приложении используется один из наиболее


распространенных архитектурных шаблонов для мобильных платформ – MVVM(Model-
View-ViewModel). Этот шаблон улучшает разделение задач и позволяет отделить логику
пользовательского интерфейса от бизнес-логики. Его целью можно считать сохранение
кода пользовательского интерфейса простым и свободным от логики приложения.
MVVM состоит из трех следующих уровней:
1. Model – отвечает за работу с данными в приложении, а также за бизнес-логику.
В мобильных приложениях этот слой часто представляет собой набор классов,
которые описывают структуру предметной области. На этом слое происходит
обмен данных с сервером или внутренним хранилищем.
2. ViewModel – отвечает за связывания слоя модели и слоя представления. Этот
уровень получает данные из модели, обрабатывает и подготавливает их для
слоя представления, а также реагирует на действия пользователя. Важной
стратегией реализации этого уровня является отделение его от представления, т.
е. ViewModel не должна знать о представлении, с которым взаимодействует.
3. View – отвечает за отображение пользовательского интерфейса и отслеживания
его событий. Этот слой получает уже готовые данные, наблюдая за
соответствующей ViewModel, а затем обновляет элементы пользовательского
интерфейса. Уровень не реагирует на действия пользователя, а только извещает
модель представления о произошедшем событии.
При использовании подхода Clean Architecture + MVVM, архитектура приложения
выглядит следующим образом (Рисунок 2.1):

17
Рисунок 2.1 – Архитектура приложения
В конечном итоге было принято решение реализовать описанную архитектуру
следующим образом (Рисунок 2.2):

Рисунок 2.2 – Архитектура приложения

2.4 Шаблон наблюдателя – MVVM + LiveData

Для корректной реализации MVVM на помощь к разработчикам приходит


LiveData, которая является реализацией шаблона наблюдателя.
LiveData – класс, который дает возможность подписаться на изменения
определённого объекта. Главной особенностью данного класса является то, что он
осведомлен о жизненном цикле компонентов приложения и самостоятельно обрабатывает
жизненный цикл объекта, что дает гарантию отсутствия утечки объекта, который
содержится в LiveData.
В данном проекте LiveData используется слоем представления для наблюдения за
данными в модели представления.

18
2.5 Пакеты приложения

На рисунке 2.3 изображена более подробная диаграмма пакетов проекта.


Основными пакетами являются App, Data. Domain и Presentation.

Рисунок 2.3 – Пакеты приложения

19
3 Реализация

Приложение было реализовано с учетом архитектуры, которая была описана ранее.

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

В приложении используются различные библиотеки. Список подключенных


библиотек приведен в таблице 3.1.

Таблица 3.1 – Список библиотек, использующихся в проекте


№ Название Описание
1. RxJava3 [1] Библиотека для использования
реактивного программирования
2. Hilt [2] Внедрение зависимостей в
приложение.
3. Glide [3] Библиотека для управления
мультимедиа и загрузки изображений,
которая объединяет декодирование
мультимедиа, кэширование, а также
объединение ресурсов в простой и
удобный интерфейс
4. Picasso [4] Библиотека для загрузки и
кэширования изображений
5. RecyclerView [5] Библиотека для отображения
динамических таблиц
6. Navigation Architecture Библиотека для реализации навигации
Component [6] по приложению
7. EventBus [7] Библиотека для обмена данными и
событиями между несвязанными
частями приложения
8. DataStore [8] Библиотека для локального хранения
данных по принципу «ключ-значение»
9. Retrofit2 [9] Библиотека для сетевого
взаимодействия
10. OkHttp3 [10] HTTP-клиент

20
11. Gson [14] Позволяет конвертировать объекты
JSON в Kotlin-объекты и наоборот

3.2 Взаимодействие с сервером

В данном проекте для реализации сетевого взаимодействия используется


библиотека Retrofit2. Для использования этой библиотеки необходимо иметь три класса:
1. POJO – класс данных, необходимый для получения JSON информации с сервера
2. Interface – определяет HTTP-запросы. Каждый метод интерфейса определяет
собой один возможный вызов API. Он должен иметь аннотацию HTTP (GET,
POST и т.д.), чтобы указать тип запроса и URL-адрес. Возвращаемое значение
оборачивается в объект класса Call с типом ожидаемого результата.
3. Retrofit.Builder – класс, создающий объект для формирования и отправки
запросов к серверу.
В качестве примера взаимодействия с сервером будет рассмотрен запрос для
получения информации о конкретной садке. Диаграмму последовательности данного
действия можно увидеть на рисунке 3.1.

Рисунок 3.1 – Просмотр садки

21
Для отправки запроса на сервер сначала был создан объект класса Retrofit с
помощью Retrofit.Builder (Листинг 3.1).
Листинг 3.1 – Создание объекта класса Retrofit

class RetrofitWithAuthenticator @Inject constructor


@OkHttpClientWithAuthenticator private val
authHttpClient: OkHttpClient,
private val gson: Gson
) {
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory
te(gson))
.addCallAdapterFactory(RxJava3CallAdapterFacto
ry

На основе интерфейса генерируется объект, который будет использоваться для


запросов на сервер (Листинг 3.2).

Листинг 3.2 – Генерация объекта, реализующего интерфейс

Код использованного интерфейса и необходимый ему метод можно увидеть ниже


(Листинг 3.3).
Листинг 3.3 – Интерфейс с методом получения садки

При вызове метода объект класса Retrofit отправляет запрос на сервер и ожидает
получения ответа. Если код ответа равен 200, то полученный JSON-файл преобразуется в
возвращаемый класс вызванного метода, при помощи библиотеки GSON [14].
Для большинства запросов необходим токен, который получает приложение при
аутентификации пользователя. Библиотека OkHttp предоставляет интерфейс Interceptor,
22
который изменяет и сокращает код исходящих запросов. В проекте используется класс
AuthenticationInterceptor, который запрашивает токен из локальной базы данных и
вставляет его в заголовок запроса. Это помогает избежать прописывания токена для
каждого нового запроса.
Бывают ситуации, что время жизни токена истекло и его нужно обновить. За это
отвечает класс RefreshTokenAuthenticator, который отправляет запрос на получение нового
токена, а затем сохраняет его в локальной базе данных (Листинг 3.4).

Листинг 3.4 – Обновление токена

val refreshToken = getRefreshToken()


val newAccessToken = try {
getNewAccessToken(refreshToken)
} catch (e: Throwable) {
if (errorIsCausedByInvalidRefreshToken(e))

EventBus.getDefault().post(RefreshTokenInvalidEvent())
return null
}
dataStoreRepository.saveNewAccessToken(newAccessToken
val newRequest = response.request.newBuilder()

3.3 Хранение данных

При помощи библиотеки DataStore в приложении создается локальное хранилище.


Оно используется для хранения информации об авторизованном пользователе, а также его
токенов.
Для начала был создан объект PreferenceKeys, в нем перечислены все поля, которые
нужно будет сохранять, они имеют тип Preferences.Key. Следующим шагом является
создание DataStore (Листинг 3.5). Т.к. DataStore разработано с использованием корутин и
Flow API, а в проекте для поддержки асинхронных запросов используется RxJava,
необходимо было подключить дополнительную библиотеку RxPreferenceDataStore.
Листинг 3.5 – создание DataStore

23
Для сохранения данных используется функция updateDataAsync(), которая
обновляет значения. Чтобы извлечь данные, используется функция readData(), которая
возвращает Flowable, после этого вызывается функция firstOrError(), чтобы получить
результат типа Single.

3.4 Навигация

Для реализации навигации по приложению была использована библиотека


Navigation Architecture Component от Google. Компонент навигации состоит из трех
основных частей:
1. Граф навигации – файл XML, хранящий в себе информацию, связанную с
навигацией, а именно отдельные области содержимого приложения, которые
называются destinations, и возможные пути, которые пользователь будет
использовать.
2. NavHost – контейнер, отображающий пункты назначения из графа навигации.
3. NavController – объект, управляющий перемещениями контента мест
назначений в NavHost.
Для начала работы с навигацией необходимо создать XML-файл графа и объявить
фрагменты, между которыми будет происходить переход (Листинг 3.6). Во фрагментах
нужно описать переходы, а также объявить аргументы, которые требуется передать на
экран. Навигация также позволяет передавать аргументы назад по стеку, используя
previousBackStackEntry.savedStateHandle с методами set() и get().
Рассмотрим пример использования навигации для редактирования садки. Садка
содержит в себе одну или несколько номенклатур, которые возможно изменять. Нажимая
на элемент списка, пользователь попадает на экран редактирования номенклатуры,
передав на него в качестве аргумента нужную номенклатуру. Поскольку навигация
представляет собой однонаправленный граф, измененную номенклатуру нельзя передать
обратно в качестве обычного аргумента, без повторного открытия экрана с садкой.
Поэтому передача осуществляется назад по стеку с помощью
previousBackStackEntry.savedStateHandle.set().
На рисунке 3.2 изображена логика переходов между экранами. Точка входа и
выхода на диаграмме отражает вход и выход в аккаунт пользователя. Выход из
приложения возможен в любой момент.

24
Рисунок 3.2 – Карта переходов между экранами

25
Листинг 3.6 – Граф навигации на примере экранов с садкой и номенклатурой

<navigation
xmlns:android="http://schemas.android.com/apk/res/
android"
xmlns:app="http://schemas.android.com/apk/res-
auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/app_navigation">

<fragment
android:id="@+id/nomenclatureFragment"
android:name="ai.ntr.kamaz.presentation
.nomenclature.NomenclatureFragment"
android:label="@string/fragment_nomenclature_label"
tools:layout="@layout/fragment_nomenclature"
<argument
android:name="nomenclature"
app:argType="ai.ntr.kamaz.domain.entity
.SchichtNomenclature"
app:nullable="true" />
<argument
android:name="oldNomenclatureId"
app:argType="integer"/>
</fragment>

<fragment
android:id="@+id/schichtFragment"
android:name="ai.ntr.kamaz.presentation
.schicht.SchichtFragment"
android:label="@string/fragment_new_schicht_label"
tools:layout="@layout/fragment_schicht">
<argument
android:name="id"
app:argType="string"
app:nullable="true" />
<action
android:id="@+id/action_schichtFragment_to_
nomenclatureFragment"

3.5 Боковое меню

В проекте присутствует боковое меню, реализованное через компонент Navigation


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

26
Для того чтобы добавить Navigation Drawer в свой проект, в xml-файл главной
активности был добавлен DrawerLayout, содержащий в себе AppBar, компонент для
отображения контента и NavigationView. В классе MainActivity необходимо провести
инициализацию компонентов: NavController, DrawerLayout, NavigationView, а также
AppBarConfiguration, который используется для управления поведением кнопок в меню.
NavigationView в разметке xml-файла было присвоено заранее созданное меню
(Листинг 3.7), а также добавлен слушатель нажатия по элементам, который осуществляет
навигацию на нужные экраны.

Листинг 3.7 – XML-файл меню

<menu
xmlns:android="http://schemas.android.com/apk/res/andr
oid"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:id="@+id/menu_top">
<item
android:id="@+id/journalFragment"
android:icon="@drawable/journal"
android:title="@string/journal_tp"
android:iconTint="@color/white"/>
<item
android:id="@+id/batchesFragment"
android:icon="@drawable/products"
android:title="@string/products"
</group>
<group android:id="@+id/menu_bottom">
<item
android:id="@+id/loginFragment"
android:icon="@drawable/exit"
В данном проекте необходимо было отключить возможность открытия меню на
экране авторизации и восстановления пароля. Это было сделано при помощи добавления к
navController слушателя смены экранов (Листинг 3.8).
Листинг 3.8 – Блокировка бокового меню и скрытие AppBar

if (destination.id == R.id.loginFragment ||
destination.id == R.id.resetPasswordFragment) {
27
Рисунок 3.3 – Скриншот бокового меню

3.6 Календарь

Для фильтрации журнала ТП и списка партий необходим был календарь, у


которого была бы возможность выбора ограниченного диапазона дат. Наиболее похожим
на макет вариантом был календарь, предоставляемый библиотекой CosmoCalendar. Но его
внешний вид все равно отличался от требуемого и в нем была возможность выбора только
одной даты, а не их диапазона.
Для решения этих проблем была проведена модификация библиотеки. Были
внесены изменения в некоторые элементы View, например, стили заголовков, цвета ячеек
и т.д. Также добавлена возможность выбора диапазона дат (Листинг 3.9).

28
Листинг 3.9 – Установка максимальной и минимальной даты

fun setMinDate(minDate: Calendar?) {


val monthsToBeRemoved: MutableList<Month> = ArrayList()
for (month in months) {
for (day in month.getDays()) {
if (!day.isDisabled) {
day.isDisabled =
CalendarUtils.isDayDisabledByMinDate(day, minDate)
}
}
if (allDaysInMonthAreDisabled(month)) {
monthsToBeRemoved.add(month)
}
}
months.removeAll(monthsToBeRemoved)
notifyDataSetChanged()
}

fun setMaxDate(maxDate: Calendar?) {


val monthsToBeRemoved: MutableList<Month> = ArrayList()
for (month in months) {
for (day in month.getDays()) {
if (!day.isDisabled) {
day.isDisabled =
CalendarUtils.isDayDisabledByMaxDate(day, maxDate)
}
}
if (allDaysInMonthAreDisabled(month)) {

Рисунок 3.4 – Скриншот календаря

29
3.7 Добавление фотографий

При создании садки пользователь может добавлять фотографию из двух


источников: изображение из галереи или снимок, снятый с помощью камеры. Для этого
был создан контракт PickImageFromSourceContract, имеющий тип
ActivityResultContract<Unit, Uri?>. В нем происходит создания массива намерений, в
который кладется намерение для выбора изображения из памяти устройства
(ACTION_GET_CONTENT с типом image/*) и запуска камеры
(ACTION_IMAGE_CAPTURE).
В системе Android, когда существует больше двух приложений, которые отвечают
на отправленное намерение, пользователю дается возможность выбрать и сохранить его
по умолчанию. Это может привести к некорректному опыту использования приложения,
например, когда пользователь сохранил выбор фотографии из галереи, а затем захотел
сделать ее с помощью камеры. Для решения этой проблемы используется createChooser,
который создает диалоговое окно выбора и заставляет пользователя каждый раз выбирать
нужное приложение.
После действия пользователя, результат представляет собой Uri необходимого
изображения, из которого можно получить Bitmap. Для загрузки фотографий на сервер,
они должны быть преобразованы в формат Base64. Чтобы получить строку Base64,
полученный Bitmap необходимо разбить на массив байтов, а затем закодировать его с
помощью Base64.encodeToString() (Листинг 3.10).

Листинг 3.10 – Получение Base64 из Bitmap

val byteArrayOutputStream = ByteArrayOutputStream()


bitmap.compress(Bitmap.CompressFormat.JPEG, 100

30
Рисунок 3.5 – Выбор источника добавления фотографии.

3.8 Списки

Для отображения списков с данными в приложении используются RecyclerView.


На экране создания и редактирования садки их находятся сразу два – для номенклатур и
фотографий.
Рассмотрим использование RecyclerView на примере слайдера для фотографий.
Для начала был создан класс SchichtPhotoRecyclerAdapter с типом
RecyclerView.Adapter<RecyclerView.ViewHolder>, который будет использоваться в
качестве адаптера. В его конструктор необходимо передавать список фотографий и
слушатель нажатия на кнопку удаления изображения, который имеет тип
собственноручно созданного интерфейса OnDeletePhotoClick. Элемент списка
представляет собой отдельный XML-файл, в котором содержится карточка с ImageView и
FloatImageButton. Загрузка фотографии в ImageView происходит с помощью
использования библиотеки Picasso.

31
Объект адаптера необходимо создать и инициализировать во фрагменте садки, а
затем назначить нужному RecyclerView. Здесь же происходит инициализация слушателя
нажатия кнопки у элемента

3.9 Отправка событий между несвязанными классами

EventBus – это библиотека, которая обеспечивает централизованную связь с


несвязанными классами всего несколькими строками кода, упрощая код, удаляя
зависимости и ускоряя разработку приложений.
Основными функциями этого приложения являются:
1. Доставка событий в основной поток Android: при взаимодействии с
пользовательским интерфейсом EventBus может доставлять события в
основной поток независимо от того, как событие было опубликовано.
2. Доставка фоновых потоков: библиотека может использовать фоновые
потоки, чтобы избежать блокировки пользовательского интерфейса, во
время выполнения длительных задач.
Пример использования данной библиотеки в проекте можно рассмотреть на случае
ошибки обновления токена из-за недействительного рефреш-токена. Для начала был
создан класс RefreshTokenInvalidEvent для этого события.
Если количество попыток обновления токена превышает допустимое значение или
сервер возвращает ошибку, которая означает, что рефреш-токен недействительный, то
происходит публикация нужного события (Листинг 3.11)

Листинг 3.11 – Публикация события

if (responseCount(response) >
MAX_AMOUNT_OF_REFRESH_TRIES) {

EventBus.getDefault().post(RefreshTokenInvalidEvent())
return null
}
val refreshToken = getRefreshToken()
val newAccessToken = try {
getNewAccessToken(refreshToken)
} catch (e: Throwable) {

32
В MainViewModel был объявлен и аннотирован метод подписки на событие. В
данном случае, необходимо было удалить данные пользователя в локальном хранилище и
выйти из аккаунта пользователя на экран авторизации (Листинг 3.12).

Листинг 3.12 – Регистрация события

@Subscribe
fun onRefreshTokenInvalid(event:
RefreshTokenInvalidEvent) {
clearUserDataUseCase.invoke(ClearUserDataParams())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result ->
result.onSuccess {
_name.postValue("")
_userIsNotSignedIn.postValue(
Также необходимо зарегистрировать и отменить регистрацию событий с учетом
жизненного цикла активности. В MainViewModel в функции init() происходит
регистрация, а в функции onCleared() ее отмена.

3.10 Реактивное программирование

RxJava — это библиотека реактивного программирования для создания


асинхронных программ и программ-событий с использованием наблюдаемых
последовательностей.
RxJava состоит из трех основных элементов:
1. Observable – источник потока данных (Оратор).
2. Operator – имеет возможность изменять данные из одной формы в другую
(Переводчик).
3. Observer – наблюдатель данных (Слушатель). Когда состояние Observable
изменяется все Observer объекты, подписанные на него, получают уведомление.

В текущем проекте также используется Single, поведение которого отличается от


Observer тем, что Single может выдавать только одно успешное значение или ошибку.
Рассмотрим пример получения садки с использованием реактивного
программирования.

33
В репозитории садки есть метод, возвращающий информацию о садке по ее id, с
типом Single<SchichtDetails>. Этот метод вызывается в юзкейсе GetSchichtByIdUseCase.
При получении успешного значения, оно оборачивается в kotlin.Result.success(), а при
получении ошибки в kotlin.Result.failure().
Листинг 3.13 – Юзкейс получения садки

BaseUseCase<Single<Result<SchichtDetails>>,
GetSchichtByIdParams> {
override fun invoke(params: GetSchichtByIdParams
Single<Result<SchichtDetails>> =
schichtRepository.getSchicht(params.id
Result.success(it)

Метод из указанного выше юзкейса вызывается в SchichtViewModel.

Листинг 3.14 – Вызов метода юзкейса

34
getSchichtByIdUseCase.invoke(GetSchichtByIdParams(id))
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result ->
result
.onSuccess { schichtInfo ->
_schicht.value = schichtInfo
_schicht.value?.schichtNomenclature?.let {
_nomenclatureList.value =
it as
ArrayList<SchichtNomenclature>
}
_schicht.value?.photos?.let {
_photoList.value = it as
ArrayList<SchichtPhoto>
}
_schichtSuccess.call()
_isFinishedLoading.call()
}
.onFailure {
_schichtError.value = when (it
is ErrorEntity.ServiceUnavailable
-> {
BaseError.ErrorNetwork
}
else -> {
SchichtFragment.Companion.GetSchichtError
}
}

35
ЗАКЛЮЧЕНИЕ

В приложение был добавлен новый функционал для работы с садкой в процессе


термической обработки изделия. Задачи, поставленные в рамках проекта, были успешно
выполнены: проведен анализ требований заказчика, разработана архитектура и самое
главное – реализован необходимый функционал.
В данный момент приложение закончено и находится на стадии введения в
эксплуатацию.

36
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ ЛИТЕРАТУРЫ

1. RxJava3 // GitHub – [Б. м.], 2022. URL:


https://github.com/ReactiveX/RxJava
2. Dependency injection with Hilt // Android Developers – [Б. м.], 2022. URL:
https://developer.android.com/training/dependency-injection/hilt-android
3. Glide // GitHub – [Б. м.], 2022. URL:
https://github.com/bumptech/glide
4. Picasso // GitHub – [Б. м], 2022. URL:
https://github.com/square/picasso
5. Create dynamic lists with RecyclerView // Android Developers – [Б. м], 2022.
URL: https://developer.android.com/guide/topics/ui/layout/recyclerview
6. Get started with the Navigation component // Android Developers – [Б. м], 2022.
URL: https://developer.android.com/guide/navigation/navigation-getting-started
7. EventBus // GitHub – [Б. м], 2021. URL:
https://github.com/greenrobot/EventBus
8. DataStore // Android Developers – [Б. м], 2022. URL:
https://developer.android.com/topic/libraries/architecture/datastore
9. Retrofit2 // GitHub – [Б. м], 2020. URL:
https://github.com/square/retrofit
10. OkHttp // GitHub – [Б. м], 2022. URL:
https://square.github.io/okhttp/
11. Meet Android Studio // Android Developers – [Б. м], 2021. URL:
https://developer.android.com/studio/intro
12. Eclipse for Android Developers // Eclipse Foundation – [Б. м], 2022. URL:
https://www.eclipse.org/downloads/packages/release/neon/m6/eclipse-android-
developers
13. IntelliJ IDEA // Jet Brains – [Б. м], 2022. URL:
https://www.jetbrains.com/idea/
14. GSON // GitHub – [Б. м], 2022. URL:
https://github.com/google/gson
15. Develop Android apps with Kotlin // Android Developers – [Б. м], 2022. URL:
https://developer.android.com/kotlin#:~:text=Kotlin%20is%20a%20modern
%20statically,Get%20started

37
16. Чистая архитектура // Р. С. Мартин – [Б. м.], 2012. URL:
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

38
ПРИЛОЖЕНИЕ A

Скриншоты реализованного приложения

Рисунок А.1 – Создание садки Рисунок А.2 – Редактирование садки

Рисунок А.3 – Садка на Рисунок А.4 – Садка на этапе


этапе создана завершить ТП

39
Рисунок А.5 – Календарь Рисунок А.6 – Контроль закалки

Рисунок А.7 – Завершение ТП Рисунок А.8 – Номенклатура

40
Рисунок А.8 – Боковое меню Рисунок А.10 – Садка на этапе закалка

Рисунок А.11 – Запуск моечной машины

41
Рисунок А.12 – Этапы ТП садки

42
43

Вам также может понравиться