Как стать автором
Поиск
Написать публикацию
Обновить

«Open Tracker: как разработать Android-приложение для автоматического трекинга коммерческих представителей. Часть 2»

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров967

Введение

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

Дизайн и структура интерфейса

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

  1. OverView — главный информационный экран

  2. Log — журнал событий

  3. Settings — настройки приложения

Навигация между экранами реализована с помощью Bottom Navigation Bar, что обеспечивает интуитивно понятное взаимодействие.

Главные экраны приложения
Главные экраны приложения

Экран OverView

На главном экране отображается:

  • Статус трекера (Запущен/Ожидает/Остановлен)

  • Время последнего получения координат GPS

  • Время последнего определения сотовых вышек (в текущей версии не используется)

  • Статус пакетов данных (готовы к отправке или отправлены)

Особенность: кнопка для немедленной отправки накопленных пакетов, что полезно для тестирования и отладки (в текущей версии не используется).

Экран Log

Журнал событий отображает последние 60 записей с визуальными метками:

  • GPS — получение координат

  • GSM — данные сотовых вышек

  • LOG — системные события

Экран Settings

Настройки включают:

  • Поля для ввода логина, пароля и адреса сервера

  • Переключатель постоянного трекинга (только для тестовых целей)

Работа с системными разрешениями

Для корректной работы приложения требуются следующие разрешения:

  • POST_NOTIFICATIONS (уведомления)

  • ACCESS_FINE_LOCATION (точное местоположение)

  • ACCESS_BACKGROUND_LOCATION (геолокация в фоне)

  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (отключение оптимизации батареи)

При первом запуске пользователь последовательно проходит через два экрана:

  1. PermissionScreen — запрос необходимых разрешений

  2. BatteryOptScreen — настройки оптимизации батареи

Экраны работы с разрешениями
Экраны работы с разрешениями

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

@Composable
fun TrackerApp() {
    TrackerTheme {
        val context = LocalContext.current
        var showPermissionScreen by remember {
            mutableStateOf(!context.hasAllPermissions())
        }

        var showBatteryOptScreen by remember {
            mutableStateOf(context.isBatteryOptimizationEnabled())
        }


        when {
            showPermissionScreen -> {
                PermissionScreen(
                    onDismiss = { showPermissionScreen = false },
                    onOpenSettings = { context.openAppSettings() }
                )
            }

            showBatteryOptScreen -> {
                BatteryOptScreen (
                    onDismiss = { showBatteryOptScreen = false },
                    onOpenBatteryOptSettings = { context.openBatteryOptimizationSettings() }
                )
            }

            else -> {
                MainScreen()
            }
        }
    }
}

Взаимодействие между Service и UI

Для передачи данных между фоновым сервисом и пользовательским интерфейсом используются:

  • В Service: два StateFlow (trackerStatetrackerHistory)

  • В ViewModel: соответствующие StateFlow (uiOverViewuiHistory)

Механизм обмена данными:

  1. В ViewModel происходит подключение к Service

  2. Запускаются корутины для сбора данных из StateFlow Service

  3. Данные трансформируются и передаются в StateFlow ViewModel

  4. UI-компоненты подписываются на StateFlow ViewModel для отображения информации

private val connection = object : ServiceConnection {
        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            val binder = service as TrackerService.LocalBinder
            boundService = binder.getService()
            isBound = true
            
            // Подписываемся на изменения состояния сервиса
            viewModelScope.launch {
                boundService?.trackerState?.collect { trackerState ->
                    _uiOverView.value = trackerState
                }
            }

            viewModelScope.launch {
                boundService?.trackerHistory?.collect{ history->
                    _uiHistory.value = history

                }
            }
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            isBound = false
            boundService = null
        }
    }

Заключение

Во второй части статьи мы рассмотрели:

  1. Минималистичный дизайн интерфейса, оптимизированный для фоновой работы

  2. Три основных экрана приложения и их функциональность

  3. Систему запроса и обработки необходимых разрешений

  4. Механизм взаимодействия между фоновым сервисом и пользовательским интерфейсом

Ключевые преимущества реализованного решения:

  • Простота использования: минимальное взаимодействие с пользователем

  • Наглядность: четкая визуализация статусов и событий

  • Гибкость: возможность расширения функциональности

Перспективы развития:

  • Реализация полноценной системы аутентификации

  • Добавление аналитики маршрутов

Исходный код проекта доступен на GitHub

Приложение Open Tracker демонстрирует, как современные Android-технологии (Compose, StateFlow, корутины) позволяют создавать эффективные решения для бизнес-задач. Разработанная архитектура может служить основой для создания подобных систем трекинга.

Теги:
Хабы:
+3
Комментарии0

Публикации

Ближайшие события