Большинство устройств на базе Android имеют встроенные датчики, которые измеряют движение, ориентацию и различные условия окружающей среды. Эти датчики способны предоставлять необработанные данные с высокой точностью и достоверностью и полезны, если вы хотите отслеживать трехмерное перемещение или позиционирование устройства или изменения в окружающей среде рядом с устройством. Например, игра может отслеживать показания датчика гравитации устройства, чтобы делать выводы о сложных жестах и движениях пользователя, таких как наклон, встряхивание, вращение или качание. Аналогично, погодное приложение может использовать датчик температуры и влажности устройства для расчета и сообщения точки росы, а приложение для путешествий может использовать датчик геомагнитного поля и акселерометр для сообщения азимута компаса.
См. следующие сопутствующие ресурсы:
Платформа Android поддерживает три основные категории датчиков:
- Датчики движения
Эти датчики измеряют силы ускорения и вращательные силы по трем осям. В эту категорию входят акселерометры, датчики силы тяжести, гироскопы и датчики вектора вращения.
- Датчики окружающей среды
Эти датчики измеряют различные параметры окружающей среды, такие как температура и давление окружающего воздуха, освещенность и влажность. В эту категорию входят барометры, фотометры и термометры.
- Датчики положения
Эти датчики измеряют физическое положение устройства. В эту категорию входят датчики ориентации и магнитометры.
Вы можете получить доступ к датчикам, доступным на устройстве, и получить необработанные данные датчиков, используя Android sensor framework. Sensor framework предоставляет несколько классов и интерфейсов, которые помогут вам выполнять широкий спектр задач, связанных с датчиками. Например, вы можете использовать sensor framework для выполнения следующих действий:
- Определите, какие датчики доступны на устройстве.
- Определите возможности отдельного датчика, такие как его максимальный диапазон, производитель, требования к питанию и разрешение.
- Собирайте необработанные данные датчиков и определите минимальную скорость, с которой вы будете получать данные датчиков.
- Регистрация и отмена регистрации прослушивателей событий датчиков, отслеживающих изменения датчиков.
В этой теме представлен обзор датчиков, доступных на платформе 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). Реализация этого датчика различается в зависимости от устройства, и этот датчик был заменен датчиком TYPE_AMBIENT_TEMPERATURE в API Level 14 | Мониторинг температуры. |
Сенсорная структура
Вы можете получить доступ к этим датчикам и получить необработанные данные датчиков, используя Android sensor framework. Sensor framework является частью пакета android.hardware
и включает следующие классы и интерфейсы:
-
SensorManager
- Вы можете использовать этот класс для создания экземпляра службы датчиков. Этот класс предоставляет различные методы для доступа к датчикам и их перечисления, регистрации и отмены регистрации прослушивателей событий датчиков и получения информации об ориентации. Этот класс также предоставляет несколько констант датчиков, которые используются для сообщения точности датчиков, установки скоростей сбора данных и калибровки датчиков.
-
Sensor
- Вы можете использовать этот класс для создания экземпляра определенного датчика. Этот класс предоставляет различные методы, которые позволяют вам определить возможности датчика.
-
SensorEvent
- Система использует этот класс для создания объекта события датчика, который предоставляет информацию о событии датчика. Объект события датчика включает следующую информацию: необработанные данные датчика, тип датчика, который сгенерировал событие, точность данных и временную метку для события.
-
SensorEventListener
- Этот интерфейс можно использовать для создания двух методов обратного вызова, которые получают уведомления (события датчика) при изменении значений датчика или при изменении точности датчика.
В типичном приложении вы используете эти API, связанные с датчиками, для выполнения двух основных задач:
- Определение датчиков и возможностей датчиков
Определение датчиков и возможностей датчиков во время выполнения полезно, если в вашем приложении есть функции, которые зависят от определенных типов датчиков или возможностей. Например, вы можете захотеть определить все датчики, которые присутствуют на устройстве, и отключить любые функции приложения, которые зависят от датчиков, которых нет. Аналогично, вы можете захотеть определить все датчики определенного типа, чтобы вы могли выбрать реализацию датчика, которая имеет оптимальную производительность для вашего приложения.
- Мониторинг событий датчиков
Мониторинг событий датчика — это способ получения необработанных данных датчика. Событие датчика происходит каждый раз, когда датчик обнаруживает изменение измеряемых им параметров. Событие датчика предоставляет вам четыре вида информации: имя датчика, вызвавшего событие, временную метку события, точность события и необработанные данные датчика, вызвавшие событие.
Наличие датчика
Хотя доступность датчиков различается от устройства к устройству, она также может различаться между версиями Android. Это связано с тем, что датчики Android были введены в ходе нескольких выпусков платформы. Например, многие датчики были введены в Android 1.5 (API Level 3), но некоторые не были реализованы и не были доступны для использования до Android 2.3 (API Level 9). Аналогично, несколько датчиков были введены в Android 2.3 (API Level 9) и Android 4.0 (API Level 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 sensor framework предоставляет несколько методов, которые позволяют вам легко определить во время выполнения, какие датчики находятся на устройстве. 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 Level 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"
. Это помогает гарантировать, что устройства смогут установить ваше приложение, даже если у них нет этого конкретного датчика. Это также лучшая практика управления проектами, которая помогает вам отслеживать функции, используемые вашим приложением. Помните, если ваше приложение использует определенный датчик, но все равно работает без датчика, вам следует обнаружить датчик во время выполнения и отключить или включить функции приложения по мере необходимости.
Система координат датчика
В целом, структура датчика использует стандартную 3-осевую систему координат для выражения значений данных. Для большинства датчиков система координат определяется относительно экрана устройства, когда устройство удерживается в ориентации по умолчанию (см. рисунок 1). Когда устройство удерживается в ориентации по умолчанию, ось X горизонтальна и направлена вправо, ось Y вертикальна и направлена вверх, а ось Z направлена к внешней стороне поверхности экрана. В этой системе координаты за экраном имеют отрицательные значения Z. Эта система координат используется следующими датчиками:

Рисунок 1. Система координат (относительно устройства), используемая API датчика.
Самое важное, что нужно понять об этой системе координат, это то, что оси не меняются местами при изменении ориентации экрана устройства, то есть система координат датчика никогда не меняется при перемещении устройства. Это поведение такое же, как и поведение системы координат OpenGL.
Еще один момент, который нужно понять, заключается в том, что ваше приложение не должно предполагать, что естественная (по умолчанию) ориентация устройства — портретная. Естественная ориентация для многих планшетных устройств — альбомная. И система координат датчика всегда основана на естественной ориентации устройства.
Наконец, если ваше приложение сопоставляет данные датчика с отображением на экране, вам необходимо использовать метод getRotation()
для определения поворота экрана, а затем использовать метод remapCoordinateSystem()
для сопоставления координат датчика с координатами экрана. Это необходимо сделать, даже если в вашем манифесте указано только портретное отображение.
Примечание: Некоторые датчики и методы используют систему координат, которая является относительной к системе отсчета мира (в отличие от системы отсчета устройства). Эти датчики и методы возвращают данные, которые представляют движение устройства или его положение относительно Земли. Для получения дополнительной информации см. метод getOrientation()
, метод getRotationMatrix()
, датчик ориентации и датчик вектора вращения .
Датчик ограничения скорости
Чтобы защитить потенциально конфиденциальную информацию о пользователях, если ваше приложение ориентировано на 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, на нем должна быть установлена Revision 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()
убедитесь, что вы выбрали скорость доставки, подходящую для вашего приложения или варианта использования. Датчики могут предоставлять данные с очень высокой скоростью. Разрешение системе отправлять дополнительные данные, которые вам не нужны, тратит системные ресурсы и расходует заряд батареи.