Диаграмма последовательности
Диаграмма последовательности (рис. 13) моделирует процесс работы пользователя с программой.
Находясь на экране со списком задач пользователь нажимает кнопку добавления задачи, инициализируя переход на фрагмент добавления задачи. Заполнив необходимые поля, пользователь нажимает кнопку сохранения задачи. Система выполняет процедуры сохранения новых данных в локальной базе и на сервере и возвращает пользователя на экран со списком задач. Работа с контекстами и координатами на карте выполняется по аналогичной последовательности.
Рис. 13. Диаграмма последовательностей
Диаграмма компонентов
Диаграмма компонентов (рисунок 14) используется для физического представления модели системы, определяет архитектуру разрабатываемой системы. Файл манифеста (AndroidManifest.xml) инкапсулирует всю архитектуру Android-приложения, его функциональные возможности и конфигурацию. В нем описываются основные компоненты системы – активности, подключаемые библиотеки, сервисы и ресиверы (приемники широковещательных сообщений).
Рис. 14. Диаграмма компонентов
Реализация системы контекстно-ориентированного планирования задач на платформе Android
Приложение реализовано для работы на устройствах под управлением операционной системы Android версии 4.0 и выше (с 14 версии API). Ориентированность на более ранние версии API даст возможность запускать приложение на большем количестве устройств, но наложит ограничения на возможности использования новых методов, предоставляемых SDK более поздних версий. Поддержка минимальной 14 версии API позволит запускать приложение на 90,4% устройств, зарегистрированных в GooglePlay Store.
Родной язык платформы Android - это Java [29]. Весь API к платформе предоставлен в виде Java библиотек [15, c. 52-53]. В качестве IDE была выбрана Andriod Studio [1] (от разработчиков самой платформы) с подключением внешнего эмулятора Genymotion на основе Virtual Box [5]. Также использовалась отладка на устройстве.
В качестве СУБД была выбрана sqlite3 – встроенный инструментарий для управления базой данных платформы Android. SQLite - это проект с открытыми исходными кодами, поддерживающий стандартные возможности обычной SQL: синтаксис, транзакции и др. Занимает очень мало места - около 250 кб. SQLite доступен на любом Android-устройстве, его не нужно устанавливать отдельно. Структура данных системы представлена в Приложении А.
Блок-схемы алгоритмов
На рис. 15 изображена блок-схема алгоритма проверки текущего контекста пользователя на необходимость уведомления о задачах. Сначала получаются текущие координаты пользователя, с использованием вспомогательного класса SimpleLocation. Затем, методом getContext класса DBWorker проверяется, попадают ли текущие координаты в радиус координат какого-либо контекста. Если пользователь находится внутри контекста, то система получает из базы задачи, привязанные к текущему контексту и с установленным флагом «Напоминать при входе в контекст». Если количество таких задач больше нуля, то система генерирует оповещение, используя встроенные классы Notification и NotificationManager.
Рис. 15. Блок-схема алгоритма проверки напоминания при смене контекста
На рис. 16 представлена блок-схема алгоритма синхронизации контекстов. Сначала система отправляет запрос на сервер, который возвращает список всех контекстов, измененных с момента последней синхронизации (метод getNewContextsFromServer()). Затем, для каждого контекста из списка достается соответствующий контекст из базы (по полю sID – серверный id элемента). Если элемент не существует в локальной базе - система добавляет его (метод insertToDB). Если элемент существует, то сравниваются даты последних изменений элемента в локальной базе и на сервере, и в зависимости от результата сравнения выполняется обновление элемента на сервере или в локальной базе.
Синхронизация задач и точек на карте происходит по аналогичному алгоритму.
Рис. 16. Процедура синхронизации контекстов
Структура классов
Для удобства разработки все классы были разбиты на пакеты (рис. 17).
Рис. 17. Структура приложения
Activities
В папке Activities расположены все активности приложения. Активность (аctivity) - класс, представляющий визуальную активность приложения и определяющий действия, которые может производить пользователь. Activity переводится как действие. Это некая сущность, олицетворяющая все, что может делать пользователь. Почти все экземпляры и разновидности активности напрямую взаимодействуют с пользователем, так что класс Activity отвечает за создание окна, в котором может быть размещен визуальный интерфейс GUI вызовом setContentView(View). В Android-приложении должен быть как минимум один класс, который был расширен (extends) от родительского класса Activity. Все активности приложения должны быть описаны в файле AndroidManifest.xml. В данном приложении три активности – форма авторизации (AuthActivity.java), форма регистрации пользователя (RegisterActivity.java) и главная активность приложения (MainActivity.java). В классе MainActivity.java находится навигационное меню, с которым пользователь может работать на всех экранах, и контейнер для фрагментов.
Fragments
Приложение реализовано с использованием фрагментов (fragments). Fragment — модульная часть активности, у которой свой жизненный цикл и свои обработчики событий. Фрагменты появились в Android с API 11, для того, чтобы разработчики могли разрабатывать более гибкие пользовательские интерфейсы. Фрагменты — это не замена активности, они не могут существовать сами по себе, а только вместе с активностью [25, c. 202-210].
Данное приложение содержит семь фрагментов, файлы которых расположены в папке Fragments. Каждый фрагмент представляет экранную форму, с которой работает пользователь: список контекстов (ContextList.java), форма добавления/редактирования контекста (ContextFragment.java), форма добавления/редактирования привязки к координатам (Point.java), простой список задач (TaskList.java), список задач с группировкой по дням недели (SeparatedFragment.java), форма добавления/редактирования задачи (Task.java) и экран настроек (Settings.java).
Adapters
Android представляет широкую палитру списковых элементов управления [25, c.180-181]. Все они являются наследниками класса android.widget.AdapterView. Это такие виджеты, как ListView (прокручиваемый список), GridView (таблица), Spinner (выпадающий список). Они могут выступать контейнерами для других элементов управления. Списковые элементы обладают возможностью привязки к данным, которые представляются в виде адаптеров. Адаптеры описывают способ отображения данных на заданную разметку [18, c.198-200]. Реализованные адаптеры расположены в папке Adapters: адаптеры списков координат (PointListAdapter.java), контекстов (ContextListAdapter.java), задач (TaskListAdapter.java, SeparatedTaskListAdapter.java), подзадач (SubTaskListAdapter.java) и адаптеры для вывода диалоговых окон выбора даты (DatePickerAdapter.java) и времени (TimePickerAdapter.java).
Providers
Все классы, необходимые для работы с базой данных расположены в папке Providers. Классы ContextContext.java, PointContext.java, TaskContext.java, SubTaskContext.java, UserContext.java представляют сущности, хранимые в базе данных (контексты, координаты на карте, задачи, подзадачи, пользователи). В классе DBWorker.java находятся методы, реализующие запросы к базе данных (получение, добавление, изменение и удаление).
RestAPI
В папке RestAPI находятся классы, реализующие запросы к серверу. Класс RequestContext.java представляет запрос на сервер и содержит адрес запроса, метод, аутентификацию (при необходимости) и тело запроса в формате JSON. Класс ResponseContext.java представляет ответ сервера и содержит код ответа и тело ответа в формате JSON. Все методы, необходимые для работы с сервером реализованы в классе WebWorker.java.
В API Android есть встроенный класс AsyncTask, предлагающий простой и удобный механизм для перемещения трудоёмких операций в фоновый поток. Класс AsyncRequest.java расширяется (extends) от класса AsyncTask и реализует функционал отправки запроса на сервер, принимая в качестве входного параметра объект класса RequestContext.java и возвращая объект класса ResponseContext.java.
Background
В папке Background находятся классы, методы которых вызываются в фоновом потоке. Класс AlarmReceiver.java расширяется от вcтроенного класса BroadcastReceiver - приёмника широковещательных сообщений [25, c.493-507]. Это компонент для получения внешних событий и реакции на них. Инициализировать передачи могут другие приложения или службы. В данном случае класс получает сообщение о наличии в системе напоминаний в заданное время и реализует функционал создания оповещения. В классе ContextNotify.java происходит проверка контекста пользователя и вывод оповещения о задачах для текущего контекста. Методы этого классы вызываются в фоновом потоке с использованием встроенного класса AsyncTask.
Widget
Виджеты — это небольшие полезные приложения, которые можно разместить на рабочем столе устройства. Они загружаются вместе с системой и работают в фоновом режиме. Зачастую виджеты распространяются в качестве дополнения, расширяющего функционал какого-либо приложения. Тем не менее, есть немало и «одиночных» виджетов, не связанных ни с какими приложениями [18, c. 509-518]. Виджет для данного приложения выводит список задач определенного контекста, если пользователь находится внутри радиуса одной из установленных точек, либо все задачи пользователя, если текущий контекст не определен.
Все классы, отвечающие за работу виджета, находятся в папке Widget. Класс AppWidget.java представляет разметку виджета и содержит обработчики нажатий на элементы. Класс WidgetRemoteViewsFactory.java является адаптером для вывода списка задач пользователя. Класс WidgetService.java отвечает за обновление списка задач в виджете.
Обмен данными с сервером
В задачах построения сложных информационных систем одной из главных проблем является обмен данными между различными подсистемами. В данном случае – это взаимодействие между клиентом (Android-приложением) и удаленным сервером.
В приложении реализовано взаимодействие с удаленным REST-сервером по протоколу HTTP. REST (Representational state transfer) – это стиль архитектуры программного обеспечения для распределенных систем, таких как World Wide Web, который, как правило, используется для построения веб-служб. Термин REST был введен одним из авторов HTTP-протокола Роем Филдингом в 2000 году [4].
Доступ к каждой единице информации в архитектуре REST определяется глобальным идентификатором – URL. Так, доступ к списку задач будет иметь вид irinn.us/api/v1.0/tasks/, доступ к списку контекстов пользователя - irinn.us/api/v1.0/contexts/. Для получения задачи с 10 id, необходимо обратиться к серверу по адресу irinn.us/api/v1.0/tasks/10.
Управление информацией сервиса основано на протоколе HTTP. Для HTTP действие над данными задается с помощью методов: GET (получить), PUT (изменить), POST (добавить), DELETE (удалить).
Вот как это будет выглядеть на примере:
GET irinn.us/api/v1.0/tasks/ — получить список всех задач пользователя.
GET irinn.us/api/v1.0/tasks/3/ — получить задачу пользователя с id = 3.
PUT irinn.us/api/v1.0/tasks/3/ — обновить задачу (данные передаются в теле запроса).
POST irinn.us/api/v1.0/tasks/ – добавить задачу (данные передаются в теле запроса).
DELETE irinn.us/api/v1.0/tasks/3/ – получить задачу с id = 3.
Для разграничения доступа пользователей к данным в запросе используется HTTP Basic Authentication. При использовании данного вида аутентификации имя пользователя и пароль включаются в состав веб-запроса (HTTP POST или HTTP GET), разделенные одним символом двоеточия, внутри base64-кодированной строки credentials.
В качестве формата данных в приложении используется JSON [25, c.278-289]. В Android содержатся готовые классы для работы с JSON в пакете json.org.
Структура JSON, отправляемых на сервер для добавления новой задачи полностью соответствует сущности Task, хранящейся в локальной базе данных (Приложение А):
{ "checked": 0, "contexts": [3, 2], "due_date": 355342131, "id": 41, "last_change": 1234343, "location_notice": 0, "notice": 0, "repeat_id": 0, "subtask": [5,6] "text": "Заплатить за интернет" } |
Листинг 1. Структура отправляемых данных
Ответ по запросу на получение списка всех задач пользователя имеет структуру:
{ "tasks": [ { "checked": 0, "contexts": [ 3 ], "due_date": 123124123, "id": 22, "last_change": 1, "location_notice": 0, "notice": 0, "repeat_id": 0, "subtask": null, "text": "Заплатить за интернет" } ] } |
Листинг 2. Структура отправляемых данных
В случае возникновения какой-либо ошибки выполнения запроса на сервере в ответ приходит код ошибки и текстовое описание в формате JSON:
{ "message": "message": "Wrong input format" } |
Листинг 3. Сообщение об ошибке
Инструкция пользователя
Для установки программы необходимо скопировать файл planium.apk в память устройства и запустить его на установку. Далее нужно следовать указаниям программы установки.
При первом запуске программы открывается форма авторизации (рис. 17). Обязательные поля – адрес email и пароль. Если пользователь зарегистрирован в системе, то при первой авторизации в приложении система загрузит все задачи и контексты пользователя с удаленного сервера в локальную базу.
Рис. 17. Форма авторизации
Если у пользователя нет аккаунта в системе, он может пройти процедуру регистрации из приложения (рис. 18). Все поля являются обязательными для заполнения. Регистрация через приложение возможна только при наличии подключении к интернету.
Рис. 18 Форма регистрации
При последующих запусках приложения проходить процедуру авторизации не нужно, система сразу открывает список задач пользователя.
При возникновении ошибок, связанных с некорректным вводом данных пользователем или отсутствием подключения к интернету система оповещает пользователя всплывающим сообщением (рис. 19).
Рис. 19. Сообщение об ошибке
На рис. 20 изображено основное навигационное меню программы. Меню выполнено с помощью компонента Navigation Driver, в соответствии с последними рекомендациями по дизайну от Google [8]. Меню содержит три секции: списки задач в привязке к дате, списки задач в привязке к контекстам и блок настроек, где пользователь может задавать контексты, вызвать процедуру синхронизации и выйти из системы.
Списки задач |
Задачи в привязке к контекстам |
Настройки приложения |
Рис. 20. Навигационное меню приложения
При клике на элемент списка «Контексты» навигационного меню пользователь переходит к списку контекстов (рис. 21). Для удобства пользователя в системе реализован одинаковый алгоритм управления всеми списками. При клике на элемент списка пользователь переходит к редактированию выбранного элемента. Для добавления нового необходимо нажать иконку в правом верхнем углу экрана. Чтобы удалить элемент, необходимо нажать на элемент и удерживать до появления контекстного меню (рис. 22).
Рис. 21. Список контекстов
Рис. 22. Контекстное меню
На рис. 23 изображен фрагмент редактирования контекста. Контекст состоит из названия и списка точек на карте. Для сохранения контекста необходимо нажать иконку галочки в правом верхнем углу экрана, для отмены – крестик.
Рис. 23. Редактирование контекста
На рис. 24 изображен фрагмент добавления/редактирования точки на карте для контекста. Для установки координат пользователь должен кликнуть в необходимое место на карте. Поле «Заголовок» обязательно для заполнения.
Рис. 24. Добавление/редактирование привязки к координатам
При клике на элемент списка «Все задачи» навигационного меню (рис. 20) пользователь переходит на список всех задач, изображенный на рис. 25. Просроченные задачи (срок задачи меньшей текущей даты) выделяются красным цветом.
Рис. 25. Все задачи пользователя
Если в настройках приложения (рис. 36) установить галочку «Показывать выполненные задачи», то они появятся на экране со списком задач (рис. 26).
Рис. 26. Список с выполненными задачами
На рис. 27 отображен экран со списком задач на текущую дату.
Рис. 27. Задачи на текущую дату
При выборе пункта меню «Неделя» отображается список задач с ткущей даты на семь дней вперед с группировкой по дням недели (рис. 28).
Рис. 28. Задачи на неделю вперед
При клике на элементы второго блока навигационного меню (рис. 20) можно просматривать задачи в привязке к установленным контекстам (рис. 29).
Рис. 29. Задачи в привязке к контексту
На рис. 30 представлено окно добавления/редактирования задачи. Задача состоит из текста задачи (единственное обязательное поле), привязке к контекстам, срока, когда эта задача должна быть выполнена. К задаче может быть привязан список подзадач. Также на задачу можно установить напоминание с периодом повтора (без повтора, ежедневно, еженедельно, ежемесячно, ежегодно) и с напоминанием при смене контекста.
Рис. 30. Фрагмент добавления задачи
Диалоговое окно выбора конекстов представлено на рис. 31. Допускается выбор одного или более варианта. На рис. 32 и рис. 33 изображены диалоговые окна выбора даты и времени для установки напоминания.
Рис. 31. Добавление привязки к контексту
Рис. 32. Установка даты напоминания
Рис. 33. Установка времени напоминания
На рис. 34 изображено оповещение о задачи, заданное на определенное время. Оповещения создаются с помощью объекта Notificatiоn и представляют собой значок с текстом в системной строке состояния. Оповещение сопровождается вибрацией и свечением светодиодных индикаторов при их наличии на устройстве.
Рис. 34. Оповещение о задаче в определенное время.
При приближении к какой-либо точке контекста система проверяет, есть ли задачи, о которых необходимо сообщить и генерирует оповещение (рис. 35).
Рис. 35. Оповещение о задаче при смене контекста
На рис. 36 изображен фрагмент с настройками системы, доступными пользователю. Пользователь может выбрать, отображать завершенные задачи в списке или нет, и задать радиус срабатывания оповещения о контексте.
Рис. 36. Настройки приложения
На рис. 37 изображен виджет приложения, который доступен для размещения как на главном экране устройства, так и на экране блокировки. Виджет отображает задачи пользователя, привязанные к текущему контексту, если пользователь находится внутри радиуса какой-либо точки, или же все задачи, если пользователь находится вне контекста. Виджет обновляет список задач раз в 30 минут, при необходимости пользователь может сам вызвать процедуру обновления, нажав на соответствующую иконку.
Рис. 37. Виджет приложения
Инструкция программиста
Приложение реализовано в среде Android Studio на языке Java с минимальной версией Android SDK 14 и выше. Приложение использует встроенный в платформу инструмент sqlite3 в качестве базы данных.
Структура приложения представлена на рис. 38.
Рис. 38. Структура проекта
Исходный код приложения находится в директории /app/src/main/java/. Здесь содержатся все рабочие классы программы. В директории /app/sr/main/res/ расположены ресурсы приложения, такие как изображения (drawable), строковые ресурсы (values) и шаблоны разметки (layout).
Манифест приложения
Файл манифеста инкапсулирует архитектуру Android-приложения и его конфигурацию [18, c.288-290]. Файл располагается в директории app/src/main/ проекта.
Корневым элементом манифеста является manifest. Помимо данного элемента обязательным элементом является тег application.
В элементе manifest в атрибуте package определяется уникальное имя пакета приложения:
package="com.example.maria.ToDo " |
Листинг 4. Имя пакета в файле AndroidManifest.xml
Элемент uses-permission описывает разрешения, которые приложению должны быть предоставлены системой для его нормального функционирования. Для работы приложения необходимы следующие разрешения:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <uses-permission android:name="android.permission.VIBRATE" /> |
Листинг 5. Необходимые разрешения
Элемент application является основным элементом манифеста и содержит множество дочерних элементов, определяющих структуру и работу приложения. В манифесте может быть только один элемент application.
Элемент activity объявляет активность. Если активность не объявлена в манифесте, она не будет видна системе и не будет запущена при выполнении приложения или будет выводиться сообщение об ошибке.
Приложение состоит из трех активностей – MainActivity. RegisterActivity, AuthActivity:
<activity android:name=".Activities.MainActivity" android:label="@string/app_name" > </activity> <activity android:name=".Activities.AuthActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Activities.RegisterActivity" android:label="@string/title_activity_register" > </activity> |
Листинг 6. Объявление активностей
При запуске приложения создается AuthActivity, в которой происходит проверка авторизации пользователя. Если процедура авторизации была пройдена ранее, осуществляется переход на MainActivity.
В элементе service объявляются службы как компоненты приложения. В системе присутствует один сервис, отвечающий за работу и обновление виджета приложения:
<service android:name=".Widget.WidgetService" android:exported="false" android:permission="android.permission.BIND_REMOTEVIEWS" /> |
Листинг 7. Объявление служб
Элемент receiver объявляет приемник широковещательных сообщений.
В приложении есть два приемника. AlarmReceiver отвечает за получение намерений от системы для создания напоминания в заданное время. AppWidget необходим для инициализации процедуры обновления виджета.
<receiver android:name=".Services.AlarmReciever" android:process=":remote" /> <receiver android:name=".Widget.AppWidget" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/new_app_widget_info" /> </receiver> |
Листинг 8. Объявление приемников широковещательных сообщений
Элемент uses-library определяет общедоступные библиотеки, с которой должно быть скомпоновано приложение. В данной системе используется библиотека для работы с картами от Google, которая должна быть прописана в файле манифеста. Для использования этой библиотеки необходимо иметь ключ разработчика, который можно получить, зарегистрировав приложение на официальном сайте [6]:
<uses-library android:name="com.google.android.maps" /> <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyCwPRFb3zxhSRw_697sXDGiHHut2xUqF9A" /> |
Листинг 9. Подключение библиотеки com.google.android.maps
Система сборки Gradle
Все проекты на платформе Java используют инструменты сборки. Gradle – система автоматической сборки, построенная на принципах Apache Ant и Apache Maven.
Gradle использует направленный ациклический граф для определения порядка выполнения задач.
Gradle был разработан для расширяемых многопроектных сборок, и поддерживает инкрементальные сборки, определяя, какие компоненты дерева сборки не изменились и какие задачи, зависимые от этих частей, не требуют перезапуска.
Сборка gradle-проекта описывается в файле build.gradle и этот файл размещается в корне проекта (/app/build.gradle):
apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion "21.1.2" defaultConfig { applicationId "com.example.maria.testnavbar" minSdkVersion 14 targetSdkVersion 21 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar', '*.aar']) compile 'com.google.android.gms:play-services:6.5.87' compile 'com.android.support:appcompat-v7:22.1.1' } |
Листинг 10. Файл build.gradle
Блок android { … } конфигурирует параметры, необходимые для андроид-сборки. Здесьуказывается версия SDK для компиляции (compileSdkVersion), а также версия инструментов для сборки (buildToolsVersion).
Внутри элемента defaultConfig { … } указывается минимальная поддерживаемая версия sdk (minSdkVersion).
Блок dependencies { … } содержит перечень всех библиотек, используемых в проекте.