Sensors API — это интерфейс платформы Android для доступа к аппаратным датчикам устройства. API предоставляет единый способ получения данных с акселерометра, гироскопа, магнитометра, датчика освещённости и других сенсоров. По данным Google, 2026, более 95% современных Android-устройств оснащены минимум тремя типами датчиков, что открывает широкие возможности для разработки контекстно-зависимых приложений.
Главное
Sensors API — это программный интерфейс Android Framework, предоставляющий разработчикам доступ к аппаратным датчикам мобильного устройства. API входит в состав Android SDK начиная с версии 1.0 и доступен через пакет android.hardware. Интерфейс абстрагирует различия между реализациями датчиков от разных производителей — Qualcomm, MediaTek, Samsung Exynos — и предоставляет единую модель работы с сенсорами.
API позволяет выполнять три ключевых операции: получать список доступных датчиков, регистрировать слушатели для получения данных и управлять частотой обновления показаний. SensorManager выступает центральной точкой доступа ко всем операциям. Система уведомляет приложение через колбэк onSensorChanged, передавая объект SensorEvent с массивом значений float.
За время существования Android API прошёл несколько этапов развития. В версии 2.3 (Gingerbread) появилась поддержка Batch Processing — группировка событий датчика для снижения энергопотребления. Android 4.0 (Ice Cream Sandwich) добавил виртуальные датчики Gravity и Linear Acceleration. Начиная с Android 8.0, система ограничила фоновый доступ к датчикам для повышения приватности.
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensorList: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
sensorList.forEach { sensor ->
Log.d("Sensors", "${sensor.name} — ${sensor.type}")
}
Не все устройства имеют одинаковый набор датчиков. Приложение должно проверять доступность конкретного сенсора перед регистрацией слушателя. Эмулятор Android поддерживает только ограниченный набор датчиков — акселерометр и магнитометр. Для тестирования остальных датчиков требуется физическое устройство. Начиная с Android 12, приложения обязаны декларировать использование датчиков в манифесте.
Android классифицирует все датчики на три категории: Motion (движение), Position (положение) и Environment (окружение). Motion-датчики включают акселерометр, гироскоп и шагомер. Position-датчики содержат магнитометр и Orientation. Environment — датчик освещённости, давления, температуры и влажности.
| Категория | Датчики | Тип (константа) | Физический/Виртуальный |
|---|---|---|---|
| Motion | Акселерометр | TYPE_ACCELEROMETER | Физический |
| Motion | Гироскоп | TYPE_GYROSCOPE | Физический |
| Motion | Шагомер | TYPE_STEP_COUNTER | Физический |
| Motion | Gravity | TYPE_GRAVITY | Виртуальный |
| Position | Магнитометр | TYPE_MAGNETIC_FIELD | Физический |
| Position | Rotation Vector | TYPE_ROTATION_VECTOR | Виртуальный |
| Environment | Освещённость | TYPE_LIGHT | Физический |
| Environment | Давление | TYPE_PRESSURE | Физический |
Акселерометр измеряет ускорение в м/с² по трём осям — X, Y и Z. Значения включают гравитацию (9.8 м/с² по оси Z в состоянии покоя). Гироскоп измеряет угловую скорость в рад/с — скорость вращения устройства вокруг каждой оси. Комбинация этих двух датчиков используется в навигации, играх и AR-приложениях.
class SensorActivity : Activity(), SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
textView.text = "X: $x, Y: $y, Z: $z"
}
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
}
Магнитометр (TYPE_MAGNETIC_FIELD) измеряет магнитное поле в микротеслах (мкТл) по трём осям. Используется как цифровой компас — в сочетании с акселерометром позволяет определить азимут устройства. Rotation Vector — виртуальный датчик, который объединяет данные гироскопа, акселерометра и магнитометра для точного определения ориентации.
Датчик освещённости (TYPE_LIGHT) измеряет уровень внешнего освещения в люксах (лк). Используется для автоматической регулировки яркости экрана. Датчик давления (TYPE_PRESSURE) измеряет атмосферное давление в гектопаскалях (гПа) — применяется в навигационных приложениях для определения высоты над уровнем моря.
Sensors API построен на архитектуре клиент-сервер. Приложение выступает клиентом, SensorManager — сервисом системы Android. Когда приложение регистрирует слушателя через registerListener, SensorManager связывается с HAL (Hardware Abstraction Layer) — низкоуровневым драйвером датчика, работающим на уровне ядра Linux.
HAL-драйвер получает сырые данные с аппаратного чипа, фильтрует шумы и передаёт их вверх по стеку — через SensorService (системный процесс) в приложение. Данные передаются в виде объекта SensorEvent, содержащего массив float-значений values и метку времени в наносекундах. Частота событий зависит от выбранного режима доставки.
При регистрации слушателя разработчик указывает желаемую задержку между событиями через константы SENSOR_DELAY_NORMAL (200 мс), SENSOR_DELAY_UI (60 мс), SENSOR_DELAY_GAME (20 мс) и SENSOR_DELAY_FASTEST (0 мс — максимальная частота). Реальная частота может отличаться — система оптимизирует энергопотребление.
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager.registerListener(
this,
sensor,
SensorManager.SENSOR_DELAY_GAME
)
Начиная с Android 2.3, датчики поддерживают пакетный режим — события накапливаются в FIFO-буфере и доставляются одним пакетом. Это позволяет процессору дольше оставаться в режиме сна, снижая энергопотребление до 60%. Размер буфера зависит от чипа датчика и указывается в поле Sensor.fifoMaxEventCount.
SensorManager — системный сервис, доступный через getSystemService(Context.SENSOR_SERVICE). Он предоставляет методы для получения списка датчиков, получения конкретного датчика по умолчанию и регистрации/отмены слушателей. SensorManager — синглтон, один экземпляр на всё приложение.
Перед использованием датчика необходимо проверить его наличие. Метод getDefaultSensor(type) возвращает null, если датчик отсутствует на устройстве. Получение null без проверки приведёт к NullPointerException при регистрации слушателя. Список всех датчиков возвращает метод getSensorList(type).
fun checkSensorAvailability(type: Int): Boolean {
val sensorManager =
getSystemService(Context.SENSOR_SERVICE) as SensorManager
return sensorManager.getDefaultSensor(type) != null
}
// Использование:
if (checkSensorAvailability(Sensor.TYPE_GYROSCOPE)) {
Log.d("Sensor", "Гироскоп доступен")
}
Слушатель регистрируется через registerListener(listener, sensor, delay). Важно: отменять слушатель необходимо в методе onPause() через unregisterListener(listener). Если этого не сделать, приложение будет продолжать получать события датчика, разряжая батарею даже в фоне. Android 8+ выводит предупреждение в logcat о незарегистрированных слушателях.
Метод onAccuracyChanged(sensor, accuracy) вызывается при изменении точности датчика. Значения: SENSOR_STATUS_ACCURACY_HIGH, MEDIUM, LOW и UNRELIABLE. При получении UNRELIABLE данные датчика следует игнорировать до восстановления точности. Например, магнитометр требует калибровки — встряхивания устройства в форме восьмёрки.
Рассмотрим практические примеры использования Sensors API в Android-приложениях на Kotlin. Первый пример — определение ориентации экрана с помощью акселерометра. Второй — считывание показаний магнитометра с калибровкой. Третий — детектор шагов с использованием шагомера.
Для определения ориентации используется комбинация акселерометра и магнитометра. Метод SensorManager.getRotationMatrix() вычисляет матрицу поворота, а getOrientation() извлекает углы pitch, roll и azimuth. Azimuth (азимут) — угол относительно магнитного севера в радианах.
val gravity = FloatArray(3)
val geomagnetic = FloatArray(3)
val rotationMatrix = FloatArray(9)
val orientation = FloatArray(3)
SensorManager.getRotationMatrix(
rotationMatrix, null, gravity, geomagnetic
)
SensorManager.getOrientation(rotationMatrix, orientation)
// orientation[0] — azimuth, [1] — pitch, [2] — roll
val azimuthDeg = Math.toDegrees(orientation[0].toDouble())
Шагомер (TYPE_STEP_COUNTER) возвращает общее количество шагов, совершённых пользователем с момента последней перезагрузки устройства. Датчик работает на аппаратном уровне — он активен даже когда приложение не запущено. Для получения шагов за сессию необходимо сохранять начальное значение и вычислять разницу.
var initialSteps = 0
var isInitialized = false
override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_STEP_COUNTER) {
if (!isInitialized) {
initialSteps = event.values[0].toInt()
isInitialized = true
}
val currentSteps = event.values[0].toInt()
val sessionSteps = currentSteps - initialSteps
Log.d("Steps", "Шагов за сессию: $sessionSteps")
}
}
Датчик освещённости позволяет адаптировать интерфейс под условия окружения. При низкой освещённости (менее 10 лк) можно переключиться в тёмную тему. При ярком солнечном свете (более 10000 лк) — увеличить контрастность. Для фильтрации шумов используется скользящее среднее по 5 последним значениям.
Android предоставляет несколько виртуальных датчиков, которые не имеют прямого аппаратного аналога. Виртуальный датчик вычисляет свои показания на основе комбинации физических сенсоров. Это снижает нагрузку на разработчика — система сама реализует алгоритмы слияния данных.
Датчик Gravity (TYPE_GRAVITY) выделяет гравитационную составляющую из показаний акселерометра с помощью low-pass фильтра. Linear Acceleration (TYPE_LINEAR_ACCELERATION) — наоборот, удаляет гравитацию и оставляет только линейное ускорение устройства. Сумма Gravity и Linear Acceleration даёт сырые показания акселерометра.
Rotation Vector — наиболее сложный виртуальный датчик. Он комбинирует данные гироскопа (высокочастотные изменения), акселерометра (вектор гравитации) и магнитометра (ориентация относительно севера). Результат — кватернион, описывающий абсолютную ориентацию устройства в пространстве. Используется в AR-приложениях и VR-шлемах.
Game Rotation Vector — упрощённая версия Rotation Vector без использования магнитометра. Это даёт более низкую точность определения азимута, но более высокую частоту обновления и стабильность. Рекомендуется для игр, где важна низкая задержка, а не абсолютная ориентация относительно севера.
Датчики — одни из самых энергоёмких компонентов устройства. Акселерометр и гироскоп при максимальной частоте опроса могут разрядить батарею за 3–4 часа непрерывной работы. Оптимизация работы с датчиками — критическая задача для любого приложения, использующего Sensors API.
Не используйте SENSOR_DELAY_FASTEST без необходимости. Для UI-анимаций достаточно SENSOR_DELAY_UI (60 мс). Для определения ориентации экрана — SENSOR_DELAY_NORMAL (200 мс). Чем выше частота, тем больше времени процессор проводит в активном состоянии. Разница между NORMAL и FASTEST составляет до 10x по энергопотреблению.
Начиная с Android 8.0 (API 26), фоновые приложения получают события датчиков с пониженной частотой. В Android 12+ фоновый доступ к датчикам Motion и Position требует разрешения BODY_SENSORS_BACKGROUND. Отменяйте регистрацию слушателя при переходе приложения в фоновый режим — это продлевает время работы устройства.
Используйте пакетную обработку через метод registerListener(listener, sensor, delay, maxReportLatencyUs). Параметр maxReportLatencyUs задаёт максимальную задержку доставки событий в микросекундах. При значении 1000000 (1 секунда) события накапливаются в FIFO-буфере датчика и доставляются раз в секунду — процессор реже выходит из сна.
Часто задаваемые вопросы
Минимальный набор — акселерометр и магнитометр. Эти два датчика присутствуют более чем на 95% устройств. Гироскоп, датчик освещённости и датчик приближения — на 70–80% современных моделей. Остальные датчики (давление, температура, влажность, шагомер) встречаются реже и зависят от ценовой категории устройства.
TYPE_ACCELEROMETER возвращает полное ускорение, включая гравитацию (9.8 м/с²). TYPE_LINEAR_ACCELERATION возвращает ускорение без гравитации — только ускорение от движения устройства. Если устройство лежит неподвижно, акселерометр покажет 9.8 м/с² по оси Z, а Linear Acceleration — 0 по всем осям.
Используйте getPackageManager().hasSystemFeature() с соответствующими константами: FEATURE_SENSOR_ACCELEROMETER, FEATURE_SENSOR_GYROSCOPE, FEATURE_SENSOR_PROXIMITY и другими. Альтернативный способ — вызвать getDefaultSensor(type) и проверить результат на null. Первый способ предпочтительнее для проверки на этапе инициализации.
Сырые данные с датчиков содержат шумы. Для сглаживания используйте low-pass фильтр: newValue = alpha * rawValue + (1 — alpha) * previousValue. Коэффициент alpha = 0.1–0.3 даёт хороший баланс между отзывчивостью и гладкостью. Для гироскопа также применяется high-pass фильтр для удаления дрейфа нуля.
Да, но с ограничениями. Начиная с Android 8.0, частота событий датчика снижается для фоновых приложений. Начиная с Android 12, требуется разрешение BODY_SENSORS_BACKGROUND для доступа к датчикам в фоне. Для фоновой работы рекомендуется использовать Foreground Service с уведомлением.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также