Большинство устройств на базе Android оснащены встроенными датчиками, измеряющими движение, ориентацию и различные условия окружающей среды. Эти датчики способны предоставлять необработанные данные с высокой точностью и достоверностью и полезны для отслеживания трёхмерного перемещения или позиционирования устройства, а также для отслеживания изменений окружающей среды рядом с устройством. Например, игра может отслеживать показания датчика гравитации устройства, чтобы распознавать сложные жесты и движения пользователя, такие как наклон, встряхивание, вращение или взмах. Аналогично, приложение для прогноза погоды может использовать датчик температуры и влажности устройства для расчёта и определения точки росы, а приложение для путешествий — датчик геомагнитного поля и акселерометр для определения азимута.
См. следующие сопутствующие ресурсы:
Платформа Android поддерживает три основные категории датчиков:
- Датчики движения
Эти датчики измеряют силы ускорения и вращения по трём осям. К этой категории относятся акселерометры, датчики силы тяжести, гироскопы и датчики вектора вращения.
- Датчики окружающей среды
Эти датчики измеряют различные параметры окружающей среды, такие как температура и давление окружающего воздуха, освещённость и влажность. К этой категории относятся барометры, фотометры и термометры.
- Датчики положения
Эти датчики измеряют физическое положение устройства. К этой категории относятся датчики ориентации и магнитометры.
Вы можете получить доступ к датчикам, доступным на устройстве, и получить необработанные данные с них, используя фреймворк датчиков Android. Фреймворк датчиков предоставляет несколько классов и интерфейсов, которые помогают выполнять широкий спектр задач, связанных с датчиками. Например, фреймворк датчиков можно использовать для следующих целей:
- Определите, какие датчики доступны на устройстве.
- Определите возможности отдельного датчика, такие как его максимальный диапазон, производитель, требования к питанию и разрешение.
- Собирайте необработанные данные датчиков и определите минимальную скорость сбора данных датчиков.
- Регистрация и отмена регистрации прослушивателей событий датчиков, отслеживающих изменения датчиков.
В этой теме представлен обзор датчиков, доступных на платформе Android, а также введение в фреймворк датчиков.
Введение в датчики
Фреймворк датчиков Android позволяет получить доступ ко многим типам датчиков. Некоторые из этих датчиков аппаратные, а некоторые — программные. Аппаратные датчики — это физические компоненты, встроенные в мобильный телефон или планшет. Они получают данные, напрямую измеряя определённые параметры окружающей среды, такие как ускорение, напряжённость геомагнитного поля или изменение угла. Программные датчики не являются физическими устройствами, хотя и имитируют аппаратные датчики. Программные датчики получают данные от одного или нескольких аппаратных датчиков и иногда называются виртуальными датчиками или синтетическими датчиками. Датчик линейного ускорения и датчик силы тяжести являются примерами программных датчиков. В таблице 1 перечислены датчики, поддерживаемые платформой Android.
Немногие устройства на базе Android оснащены всеми типами датчиков. Например, большинство мобильных телефонов и планшетов оснащены акселерометром и магнитометром, но реже встречаются устройства с барометрами или термометрами. Кроме того, устройство может быть оснащено несколькими датчиками одного типа. Например, устройство может быть оснащено двумя датчиками силы тяжести, каждый из которых имеет свой диапазон.
Таблица 1. Типы датчиков, поддерживаемые платформой Android.
Датчик | Тип | Описание | Распространенные применения |
---|---|---|---|
TYPE_ACCELEROMETER | Аппаратное обеспечение | Измеряет силу ускорения в м/ с2 , приложенную к устройству по всем трем физическим осям (x, y и z), включая силу тяжести. | Обнаружение движения (встряска, наклон и т. д.). |
TYPE_AMBIENT_TEMPERATURE | Аппаратное обеспечение | Измеряет температуру окружающего воздуха в градусах Цельсия (°C). См. примечание ниже. | Мониторинг температуры воздуха. |
TYPE_GRAVITY | Программное или аппаратное обеспечение | Измеряет силу тяжести в м/ с2 , которая прикладывается к устройству по всем трем физическим осям (x, y, z). | Обнаружение движения (встряска, наклон и т. д.). |
TYPE_GYROSCOPE | Аппаратное обеспечение | Измеряет скорость вращения устройства в рад/с вокруг каждой из трех физических осей (x, y и z). | Обнаружение вращения (вращение, поворот и т. д.). |
TYPE_LIGHT | Аппаратное обеспечение | Измеряет уровень окружающего освещения (освещенность) в люксах. | Управление яркостью экрана. |
TYPE_LINEAR_ACCELERATION | Программное или аппаратное обеспечение | Измеряет силу ускорения в м/ с2 , которая прикладывается к устройству по всем трем физическим осям (x, y и z), исключая силу тяжести. | Мониторинг ускорения вдоль одной оси. |
TYPE_MAGNETIC_FIELD | Аппаратное обеспечение | Измеряет окружающее геомагнитное поле по всем трем физическим осям (x, y, z) в мкТл. | Создание компаса. |
TYPE_ORIENTATION | Программное обеспечение | Измеряет градусы вращения устройства вокруг всех трёх физических осей (x, y, z). Начиная с API уровня 3, можно получить матрицу наклона и матрицу вращения устройства, используя датчик силы тяжести и датчик геомагнитного поля совместно с методом getRotationMatrix() . | Определение положения устройства. |
TYPE_PRESSURE | Аппаратное обеспечение | Измеряет давление окружающего воздуха в гПа или мбар. | Мониторинг изменений давления воздуха. |
TYPE_PROXIMITY | Аппаратное обеспечение | Измеряет расстояние до объекта (в см) относительно экрана устройства. Этот датчик обычно используется для определения, подносится ли телефон к уху человека. | Положение телефона во время разговора. |
TYPE_RELATIVE_HUMIDITY | Аппаратное обеспечение | Измеряет относительную влажность окружающей среды в процентах (%). | Мониторинг точки росы, абсолютной и относительной влажности. |
TYPE_ROTATION_VECTOR | Программное или аппаратное обеспечение | Измеряет ориентацию устройства, предоставляя три элемента вектора вращения устройства. | Обнаружение движения и вращения. |
TYPE_TEMPERATURE | Аппаратное обеспечение | Измеряет температуру устройства в градусах Цельсия (°C). Реализация этого датчика различается в зависимости от устройства, и в API Level 14 этот датчик был заменён датчиком TYPE_AMBIENT_TEMPERATURE | Мониторинг температур. |
Структура сенсора
Доступ к этим датчикам и сбор необработанных данных с них можно получить с помощью фреймворка Android Sensor Framework. Фреймворк Sensor Framework входит в пакет android.hardware
и включает следующие классы и интерфейсы:
-
SensorManager
- Этот класс можно использовать для создания экземпляра службы датчиков. Он предоставляет различные методы для доступа к датчикам и их перечисления, регистрации и отмены регистрации прослушивателей событий датчиков, а также получения информации об ориентации. Этот класс также предоставляет несколько констант датчиков, используемых для определения точности датчиков, настройки скорости сбора данных и калибровки датчиков.
-
Sensor
- Этот класс можно использовать для создания экземпляра конкретного датчика. Он предоставляет различные методы, позволяющие определить возможности датчика.
-
SensorEvent
- Система использует этот класс для создания объекта события датчика, предоставляющего информацию о событии датчика. Объект события датчика включает в себя следующую информацию: необработанные данные датчика, тип датчика, сгенерировавшего событие, точность данных и временную метку события.
-
SensorEventListener
- Этот интерфейс можно использовать для создания двух методов обратного вызова, которые получают уведомления (события датчика) при изменении значений датчика или при изменении точности датчика.
В типичном приложении вы используете эти API, связанные с датчиками, для выполнения двух основных задач:
- Определение датчиков и возможностей датчиков
Определение датчиков и их возможностей во время выполнения полезно, если в вашем приложении есть функции, зависящие от определённых типов или возможностей датчиков. Например, вам может потребоваться определить все датчики, присутствующие на устройстве, и отключить все функции приложения, зависящие от отсутствующих датчиков. Аналогичным образом, вам может потребоваться определить все датчики заданного типа, чтобы выбрать реализацию датчика, обеспечивающую оптимальную производительность для вашего приложения.
- Мониторинг событий датчиков
Мониторинг событий датчиков — это способ получения необработанных данных. Событие датчика происходит каждый раз, когда датчик обнаруживает изменение измеряемых им параметров. Событие датчика содержит четыре вида информации: название датчика, вызвавшего событие, временную метку события, точность события и необработанные данные датчика, вызвавшие событие.
Наличие датчика
Хотя доступность датчиков различается от устройства к устройству, она также может различаться в зависимости от версии Android. Это связано с тем, что датчики Android появлялись в течение нескольких выпусков платформы. Например, многие датчики появились в Android 1.5 (API уровня 3), но некоторые из них не были реализованы и стали доступны для использования до Android 2.3 (API уровня 9). Аналогично, несколько датчиков появились в Android 2.3 (API уровня 9) и Android 4.0 (API уровня 14). Два датчика были устарели и заменены новыми, более совершенными.
В таблице 2 представлена сводная информация о доступности каждого датчика для каждой платформы. Перечислены только четыре платформы, поскольку именно на них датчики были заменены. Датчики, отмеченные как устаревшие, по-прежнему доступны на последующих платформах (при условии, что датчик установлен на устройстве), что соответствует политике прямой совместимости Android.
Таблица 2. Доступность датчиков по платформам.
Датчик | Андроид 4.0 (Уровень API 14) | Андроид 2.3 (Уровень API 9) | Андроид 2.2 (Уровень API 8) | Андроид 1.5 (API уровня 3) |
---|---|---|---|---|
TYPE_ACCELEROMETER | Да | Да | Да | Да |
TYPE_AMBIENT_TEMPERATURE | Да | н/д | н/д | н/д |
TYPE_GRAVITY | Да | Да | н/д | н/д |
TYPE_GYROSCOPE | Да | Да | н/д 1 | н/д 1 |
TYPE_LIGHT | Да | Да | Да | Да |
TYPE_LINEAR_ACCELERATION | Да | Да | н/д | н/д |
TYPE_MAGNETIC_FIELD | Да | Да | Да | Да |
TYPE_ORIENTATION | Да 2 | Да 2 | Да 2 | Да |
TYPE_PRESSURE | Да | Да | н/д 1 | н/д 1 |
TYPE_PROXIMITY | Да | Да | Да | Да |
TYPE_RELATIVE_HUMIDITY | Да | н/д | н/д | н/д |
TYPE_ROTATION_VECTOR | Да | Да | н/д | н/д |
TYPE_TEMPERATURE | Да 2 | Да | Да | Да |
1 Этот тип датчика был добавлен в Android 1.5 (API уровня 3), но он не был доступен для использования до Android 2.3 (API уровня 9).
2 Этот датчик доступен, но он устарел.
Определение датчиков и их возможностей
Фреймворк датчиков Android предоставляет несколько методов, которые упрощают определение датчиков на устройстве во время выполнения. API также предоставляет методы, позволяющие определить возможности каждого датчика, такие как его максимальный диапазон, разрешение и требования к питанию.
Чтобы определить датчики, установленные на устройстве, необходимо сначала получить ссылку на службу датчиков. Для этого создайте экземпляр класса SensorManager
, вызвав метод getSystemService()
и передав аргумент SENSOR_SERVICE
. Например:
Котлин
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
Ява
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Затем вы можете получить список всех датчиков на устройстве, вызвав метод getSensorList()
и используя константу TYPE_ALL
. Например:
Котлин
val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
Ява
List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
Если вы хотите перечислить все датчики определенного типа, вы можете использовать другую константу вместо TYPE_ALL
, например TYPE_GYROSCOPE
, TYPE_LINEAR_ACCELERATION
или TYPE_GRAVITY
.
Вы также можете определить, есть ли на устройстве датчик определенного типа, используя метод getDefaultSensor()
и передав ему константу типа для конкретного датчика. Если на устройстве имеется более одного датчика заданного типа, один из датчиков должен быть назначен датчиком по умолчанию. Если для заданного типа датчика по умолчанию не существует, вызов метода возвращает значение null, что означает, что на устройстве нет датчика этого типа. Например, следующий код проверяет, есть ли на устройстве магнитометр:
Котлин
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) { // Success! There's a magnetometer. } else { // Failure! No magnetometer. }
Ява
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){ // Success! There's a magnetometer. } else { // Failure! No magnetometer. }
Примечание: Android не требует от производителей устройств встраивать какие-либо определенные типы датчиков в свои устройства на базе Android, поэтому устройства могут иметь широкий спектр конфигураций датчиков.
Помимо перечисления датчиков, установленных на устройстве, вы можете использовать открытые методы класса Sensor
для определения возможностей и атрибутов отдельных датчиков. Это полезно, если вы хотите, чтобы ваше приложение реагировало по-разному в зависимости от того, какие датчики или их возможности доступны на устройстве. Например, вы можете использовать методы getResolution()
и getMaximumRange()
для получения разрешения и максимального диапазона измерения датчика. Вы также можете использовать метод getPower()
для получения информации о потребляемой мощности датчика.
Два из этих публичных методов особенно полезны, если вы хотите оптимизировать приложение для датчиков разных производителей или разных версий датчиков. Например, если вашему приложению необходимо отслеживать жесты пользователя, такие как наклон и встряхивание, вы можете создать один набор правил фильтрации данных и оптимизаций для новых устройств с датчиком гравитации конкретного производителя, а другой набор правил фильтрации данных и оптимизаций для устройств без датчика гравитации, оснащенных только акселерометром. В следующем примере кода показано, как использовать методы getVendor()
и getVersion()
для этого. В этом примере мы ищем датчик гравитации, поставщиком которого является Google LLC, и который имеет номер версии 3. Если этот датчик отсутствует на устройстве, мы пытаемся использовать акселерометр.
Котлин
private lateinit var sensorManager: SensorManager private var mSensor: Sensor? = null ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) { val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY) // Use the version 3 gravity sensor. mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 } } if (mSensor == null) { // Use the accelerometer. mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) { sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) } else { // Sorry, there are no accelerometers on your device. // You can't play this game. null } }
Ява
private SensorManager sensorManager; private Sensor mSensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mSensor = null; if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){ List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY); for(int i=0; i<gravSensors.size(); i++) { if ((gravSensors.get(i).getVendor().contains("Google LLC")) && (gravSensors.get(i).getVersion() == 3)){ // Use the version 3 gravity sensor. mSensor = gravSensors.get(i); } } } if (mSensor == null){ // Use the accelerometer. if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){ mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } else{ // Sorry, there are no accelerometers on your device. // You can't play this game. } }
Другой полезный метод — метод getMinDelay()
, который возвращает минимальный временной интервал (в микросекундах), который датчик может использовать для сбора данных. Любой датчик, возвращающий ненулевое значение для метода getMinDelay()
является потоковым датчиком. Потоковые датчики собирают данные с регулярными интервалами и были представлены в Android 2.3 (API уровня 9). Если датчик возвращает ноль при вызове метода getMinDelay()
, это означает, что он не является потоковым, поскольку он отправляет данные только при изменении измеряемых параметров.
Метод getMinDelay()
полезен, поскольку позволяет определить максимальную скорость сбора данных датчиком. Если определённые функции вашего приложения требуют высокой скорости сбора данных или потокового датчика, вы можете использовать этот метод, чтобы определить, соответствует ли датчик этим требованиям, а затем включить или отключить соответствующие функции в вашем приложении.
Внимание: максимальная скорость сбора данных датчика не обязательно соответствует скорости, с которой фреймворк датчика передает данные вашему приложению. Фреймворк датчика передает данные посредством событий датчика, и на скорость, с которой ваше приложение получает события датчика, влияет ряд факторов. Подробнее см. в разделе Мониторинг событий датчика .
Мониторинг событий датчиков
Для мониторинга необработанных данных датчиков необходимо реализовать два метода обратного вызова, доступных через интерфейс SensorEventListener
: onAccuracyChanged()
и onSensorChanged()
. Система Android вызывает эти методы при возникновении следующих событий:
- Точность датчика меняется.
В этом случае система вызывает метод
onAccuracyChanged()
, предоставляя ссылку на изменившийся объектSensor
и новую точность датчика. Точность представлена одной из четырёх констант состояния:SENSOR_STATUS_ACCURACY_LOW
,SENSOR_STATUS_ACCURACY_MEDIUM
,SENSOR_STATUS_ACCURACY_HIGH
илиSENSOR_STATUS_UNRELIABLE
. - Датчик сообщает новое значение.
В этом случае система вызывает метод
onSensorChanged()
, предоставляя объектSensorEvent
. ОбъектSensorEvent
содержит информацию о новых данных датчика, включая: точность данных, датчик, сгенерировавший данные, временную метку, когда были сгенерированы данные, и новые данные, записанные датчиком.
В следующем коде показано, как использовать метод onSensorChanged()
для мониторинга данных датчика освещенности. Этот пример отображает необработанные данные датчика в TextView
, которое определено в файле main.xml как sensor_data
.
Котлин
class SensorActivity : Activity(), SensorEventListener { private lateinit var sensorManager: SensorManager private var mLight: Sensor? = null public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) } override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) { // Do something here if sensor accuracy changes. } override fun onSensorChanged(event: SensorEvent) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. val lux = event.values[0] // Do something with this sensor value. } override fun onResume() { super.onResume() mLight?.also { light -> sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL) } } override fun onPause() { super.onPause() sensorManager.unregisterListener(this) } }
Ява
public class SensorActivity extends Activity implements SensorEventListener { private SensorManager sensorManager; private Sensor mLight; @Override public final void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); } @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) { // Do something here if sensor accuracy changes. } @Override public final void onSensorChanged(SensorEvent event) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. float lux = event.values[0]; // Do something with this sensor value. } @Override protected void onResume() { super.onResume(); sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } }
В этом примере задержка данных по умолчанию ( SENSOR_DELAY_NORMAL
) указывается при вызове метода registerListener()
. Задержка данных (или частота дискретизации) управляет интервалом, с которым события датчика отправляются в ваше приложение через метод обратного вызова onSensorChanged()
. Задержка данных по умолчанию подходит для отслеживания типичных изменений ориентации экрана и составляет 200 000 микросекунд. Вы можете указать другие задержки данных, например, SENSOR_DELAY_GAME
(задержка 20 000 микросекунд), SENSOR_DELAY_UI
(задержка 60 000 микросекунд) или SENSOR_DELAY_FASTEST
(задержка 0 микросекунд). Начиная с Android 3.0 (API уровня 11), задержку также можно указать как абсолютное значение (в микросекундах).
Указанная вами задержка является лишь рекомендуемой. Система Android и другие приложения могут изменять её. Рекомендуется указывать максимально возможную задержку, поскольку система обычно использует меньшую задержку, чем указанная вами (то есть следует выбрать самую низкую частоту дискретизации, которая всё ещё соответствует потребностям вашего приложения). Использование большей задержки снижает нагрузку на процессор и, следовательно, расходует меньше энергии.
Открытого метода для определения частоты, с которой фреймворк датчиков отправляет события датчиков в ваше приложение, не существует. Однако вы можете использовать временные метки, связанные с каждым событием датчика, для расчета частоты дискретизации по нескольким событиям. После установки частоты дискретизации (задержки) изменять её не требуется. Если по какой-либо причине потребуется изменить задержку, вам придётся отменить регистрацию и заново зарегистрировать прослушиватель датчиков.
Также важно отметить, что в этом примере используются методы обратного вызова onResume()
и onPause()
для регистрации и отмены регистрации прослушивателя событий датчика. Рекомендуется всегда отключать ненужные датчики, особенно когда приложение приостановлено. В противном случае аккумулятор может разрядиться всего за несколько часов, поскольку некоторые датчики потребляют значительное количество энергии и могут быстро её расходовать. Система не будет автоматически отключать датчики при выключении экрана.
Работа с различными конфигурациями датчиков
Android не определяет стандартную конфигурацию датчиков для устройств, что означает, что производители устройств могут интегрировать любую желаемую конфигурацию датчиков в свои устройства на базе Android. В результате устройства могут включать в себя различные датчики в широком диапазоне конфигураций. Если ваше приложение использует датчик определённого типа, для его успешной работы необходимо убедиться, что этот датчик присутствует на устройстве.
У вас есть два варианта убедиться, что нужный датчик присутствует на устройстве:
- Обнаруживайте датчики во время выполнения и включайте или отключайте функции приложения по мере необходимости.
- Используйте фильтры Google Play для выбора устройств с определенными конфигурациями датчиков.
Каждый вариант обсуждается в следующих разделах.
Обнаружение датчиков во время выполнения
Если ваше приложение использует датчик определённого типа, но не полагается на него, вы можете использовать фреймворк датчиков для обнаружения датчика во время выполнения, а затем отключать или включать функции приложения по мере необходимости. Например, навигационное приложение может использовать датчик температуры, датчик давления, GPS-датчик и датчик геомагнитного поля для отображения температуры, барометрического давления, местоположения и азимута. Если устройство не имеет датчика давления, вы можете использовать фреймворк датчиков для обнаружения отсутствия датчика давления во время выполнения, а затем отключить часть пользовательского интерфейса приложения, отображающую давление. Например, следующий код проверяет наличие датчика давления на устройстве:
Котлин
private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) { // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. }
Ява
private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){ // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. }
Использование фильтров Google Play для определения конкретных конфигураций датчиков
Если вы публикуете своё приложение в Google Play, вы можете использовать элемент <uses-feature>
в файле манифеста, чтобы отфильтровать приложение от устройств, у которых нет подходящей конфигурации датчиков. Элемент <uses-feature>
содержит несколько дескрипторов оборудования, позволяющих фильтровать приложения по наличию определённых датчиков. В число датчиков, которые можно перечислить, входят: акселерометр, барометр, компас (геомагнитное поле), гироскоп, датчик света и датчик приближения. Ниже приведён пример записи манифеста, которая отфильтровывает приложения без акселерометра:
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
Если вы добавите этот элемент и дескриптор в манифест вашего приложения, пользователи увидят ваше приложение в Google Play только в том случае, если их устройство оснащено акселерометром.
Дескриптор android:required="true"
следует устанавливать только в том случае, если ваше приложение полностью использует определённый датчик. Если ваше приложение использует датчик для какой-либо функции, но всё равно работает без него, необходимо указать датчик в элементе <uses-feature>
, но при этом установить дескриптор android:required="false"
. Это гарантирует, что устройства смогут установить ваше приложение, даже если у них нет этого датчика. Это также является рекомендуемой практикой управления проектами, которая помогает отслеживать функции, используемые вашим приложением. Имейте в виду, что если ваше приложение использует определённый датчик, но всё равно работает без него, необходимо обнаружить датчик во время выполнения и включить или отключить соответствующие функции приложения.
Система координат датчика
В целом, фреймворк датчиков использует стандартную трёхосную систему координат для представления значений данных. Для большинства датчиков система координат определяется относительно экрана устройства, когда оно находится в ориентации по умолчанию (см. рисунок 1). Когда устройство находится в ориентации по умолчанию, ось X горизонтальна и направлена вправо, ось Y вертикальна и направлена вверх, а ось Z направлена к внешней стороне экрана. В этой системе координаты за экраном имеют отрицательные значения Z. Эта система координат используется следующими датчиками:

Рисунок 1. Система координат (относительно устройства), используемая API датчика.
Самое важное, что нужно понимать об этой системе координат, — это то, что оси не меняются местами при изменении ориентации экрана устройства, то есть система координат датчика никогда не меняется при перемещении устройства. Это поведение аналогично поведению системы координат OpenGL.
Ещё один важный момент: ваше приложение не должно предполагать, что естественная (по умолчанию) ориентация устройства — портретная. Для многих планшетов естественная ориентация — альбомная. Система координат сенсора всегда основана на естественной ориентации устройства.
Наконец, если ваше приложение сопоставляет данные датчика с отображаемым на экране изображением, необходимо использовать метод getRotation()
для определения поворота экрана, а затем использовать метод remapCoordinateSystem()
для сопоставления координат датчика с координатами экрана. Это необходимо сделать, даже если в манифесте указано только портретное отображение.
Примечание: Некоторые датчики и методы используют систему координат, связанную с мировой системой отсчёта (в отличие от системы отсчёта устройства). Эти датчики и методы возвращают данные, отражающие движение или положение устройства относительно Земли. Подробнее см. в описаниях методов getOrientation()
и getRotationMatrix()
, Orientation Sensor и Rotation Vector Sensor .
Ограничение скорости сенсора
Для защиты потенциально конфиденциальной информации о пользователях, если ваше приложение предназначено для Android 12 (уровень API 31) или выше, система накладывает ограничение на частоту обновления данных с некоторых датчиков движения и положения. Эти данные включают значения, регистрируемые акселерометром , гироскопом и датчиком геомагнитного поля устройства.
Предел частоты обновления зависит от способа доступа к данным датчика:
- При вызове метода
registerListener()
для мониторинга событий датчика частота опроса датчика ограничена 200 Гц. Это справедливо для всех перегруженных вариантов методаregisterListener()
. - Если вы используете класс
SensorDirectChannel
, частота дискретизации датчика ограничивается значениемRATE_NORMAL
, которое обычно составляет около 50 Гц.
Если вашему приложению требуется собирать данные датчика движения с большей частотой, необходимо объявить разрешение HIGH_SAMPLING_RATE_SENSORS
, как показано в следующем фрагменте кода. В противном случае, если ваше приложение попытается собирать данные датчика движения с большей частотой без объявления этого разрешения, возникнет исключение SecurityException
.
AndroidManifest.xml
<manifest ...> <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/> <application ...> ... </application> </manifest>
Лучшие практики доступа к датчикам и их использования
При проектировании реализации датчика обязательно следуйте рекомендациям, изложенным в этом разделе. Эти рекомендации являются рекомендуемыми для всех, кто использует фреймворк датчиков для доступа к датчикам и сбора их данных.
Собирайте данные с датчиков только на переднем плане
На устройствах под управлением Android 9 (уровень API 28) и выше приложения, работающие в фоновом режиме, имеют следующие ограничения:
- Датчики, использующие режим непрерывной передачи данных, такие как акселерометры и гироскопы, не получают события.
- Датчики, использующие режимы оповещения об изменении или однократного оповещения, не получают события.
Учитывая эти ограничения, лучше всего обнаруживать события датчиков, когда ваше приложение находится на переднем плане или является частью службы переднего плана .
Отменить регистрацию прослушивателей датчиков
Обязательно отменяйте регистрацию прослушивателя датчика после завершения его использования или приостановки его активности. Если прослушиватель датчика зарегистрирован и его активность приостановлена, датчик продолжит собирать данные и использовать ресурсы батареи, пока вы не отмените регистрацию датчика. В следующем коде показано, как использовать метод onPause()
для отмены регистрации прослушивателя:
Котлин
private lateinit var sensorManager: SensorManager ... override fun onPause() { super.onPause() sensorManager.unregisterListener(this) }
Ява
private SensorManager sensorManager; ... @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); }
Для получения дополнительной информации см. unregisterListener(SensorEventListener)
.
Тест с эмулятором Android
Эмулятор Android включает в себя набор виртуальных датчиков, которые позволяют тестировать такие датчики, как акселерометр, датчик температуры окружающей среды, магнитометр, датчик приближения, датчик освещенности и другие.
Эмулятор использует подключение к устройству Android, на котором установлено приложение SdkControllerSensor . Обратите внимание, что это приложение доступно только на устройствах под управлением Android 4.0 (API уровня 14) и выше. (Если устройство работает под управлением Android 4.0, на нём должна быть установлена версия 2.) Приложение SdkControllerSensor отслеживает изменения показаний датчиков на устройстве и передаёт их в эмулятор. Затем эмулятор преобразуется в соответствии с новыми значениями, полученными от датчиков на вашем устройстве.
Исходный код приложения SdkControllerSensor можно просмотреть по следующему адресу:
$ your-android-sdk-directory/tools/apps/SdkController
Чтобы передать данные между вашим устройством и эмулятором, выполните следующие действия:
- Проверьте, включена ли на вашем устройстве отладка по USB .
- Подключите устройство к компьютеру разработчика с помощью USB-кабеля.
- Запустите приложение SdkControllerSensor на вашем устройстве.
- В приложении выберите датчики, которые вы хотите эмулировать.
Выполните следующую команду
adb
:- Запустите эмулятор. Теперь вы сможете применять преобразования к эмулятору, перемещая устройство.
$ adb forward tcp:1968 tcp:1968
Примечание: если действия, выполняемые вами на физическом устройстве, не приводят к преобразованию эмулятора, попробуйте еще раз выполнить команду adb
из шага 5.
Более подробную информацию см. в руководстве по эмулятору Android .
Не блокируйте метод onSensorChanged()
Данные датчиков могут меняться с высокой частотой, поэтому система может вызывать метод onSensorChanged(SensorEvent)
довольно часто. Рекомендуется выполнять как можно меньше действий в методе onSensorChanged(SensorEvent)
чтобы не блокировать его. Если вашему приложению требуется фильтрация или сокращение данных датчиков, эту работу следует выполнять вне метода onSensorChanged(SensorEvent)
.
Избегайте использования устаревших методов или типов датчиков.
Несколько методов и констант устарели. В частности, тип датчика TYPE_ORIENTATION
устарел. Для получения данных об ориентации следует использовать метод getOrientation()
. Аналогично, тип датчика TYPE_TEMPERATURE
устарел. На устройствах под управлением Android 4.0 вместо него следует использовать тип датчика TYPE_AMBIENT_TEMPERATURE
.
Проверьте датчики перед их использованием
Всегда проверяйте наличие датчика на устройстве, прежде чем пытаться получить с него данные. Не стоит полагаться на наличие датчика только потому, что он часто используется. Производители устройств не обязаны устанавливать какие-либо специальные датчики на свои устройства.
Тщательно выбирайте задержки датчиков
При регистрации датчика с помощью метода registerListener()
убедитесь, что выбранная вами частота передачи данных соответствует вашему приложению или варианту использования. Датчики могут предоставлять данные с очень высокой частотой. Если разрешить системе отправлять дополнительные данные, которые вам не нужны, это приведет к нерациональному использованию системных ресурсов и заряда батареи.