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("Сенсори", "${sensor.name} — ${sensor.type}")
}
Не всі пристрої мають однаковий набір датчиків. Програма повинна перевіряти доступність конкретного сенсора перед реєстрацією слухача. Емулятор Android підтримує лише обмежений набір датчиків — акселерометр та магнітометр. Для тестування інших датчиків потрібен фізичний пристрій. Починаючи з Android 12, програми зобов'язані декларувати використання датчиків у маніфесті.
Android класифікує всі датчики на три категорії: Motion, Position та Environment. Датчики Motion включають акселерометр, гіроскоп та крокомір. Датчики Position містять магнітометр та орієнтацію. Датчики 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("Сенсор", "Гіроскоп доступний")
}
Слухач реєструється через 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("Кроки", "Кроків за сесію: $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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також