Содержание
Современные устройства на базе Android оснащаются самыми различными датчиками, начиная от акселерометра и, заканчивая датчиками контроля качества воздуха. При этом, различные устройства могут содержать различное количество датчиков. В этой части мы рассмотрим работу с основными датчиками устройства на базе Android.
Общие принципы работы с датчиками
Все доступные для работы интерфейсы датчиков располагаются в пространстве имен Microsoft.Maui.Devices.Sensors
.
Для того, чтобы получить доступ к данным с датчиков, приложение должно подучить разрешение HIGH_SAMPLING_RATE_SENSORS
.
Для всех датчиков необходимо установить скорость обновления данных. В .NET MAUI для этого используется перечисление SensorSpeed
, которое содержит следующие значения:
Имя | Значение | Описание | Интервал обновления |
---|---|---|---|
Default |
0 |
Скорость датчика по умолчанию устройства. | 200 мс |
UI |
1 |
Скорость, подходящая для общего пользовательского интерфейса. | 60 мс. |
Game |
2 |
Подходит для игр. | 20 мс |
Fastest |
3 |
Как можно быстрее получить данные датчика. | 5 мс |
Используя конкретные реализации интерфейсов датчиков работа с ними строится по общему алгоритму:
- Проверяется поддержка того или иного датчика на устройстве. Для этого используется свойство
IsSupported
- Проверяется отслеживаются ли в данный момент показания датчика. Для этого используется свойство
IsMonitoring
- Если показания не отслеживаются, то приложение подписывается на событие датчика
ReadingChanged
(или аналогичное) и вызывается методStart()
с параметром скорости обновления (одним из значенийSensorSpeed
) - Если приложение заканчивает работу, то приложение отписывается от события и вызывается метод
Stop()
.
Конечно, каждый датчик возвращает свои значения, например, акселерометр возвращает вектор ускорения, барометр — давление и т.д. Но принцип чтения данных один и тот же. Теперь перейдем к реализации приложения.
Проверка датчиков на устройстве
Создадим новое приложение Blazor Hybrid и добавим в файл Platforms/Android/MainApplication.cs необходимое разрешение:
using Android.App; using Android.Runtime; [assembly: UsesPermission(Android.Manifest.Permission.HighSamplingRateSensors)] //добавляем разрешение namespace BlazorSensors { [Application] public class MainApplication : MauiApplication { public MainApplication(IntPtr handle, JniHandleOwnership ownership) : base(handle, ownership) { } protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); } }
Теперь изменим код компонента Home
следующим образом:
@page "/" @using Microsoft.Maui.Devices.Sensors <h1>Датчики</h1> <table class="table-bordered"> <thead> <tr> <th>Датчик</th> <th>Состояние</th> </tr> </thead> <tbody> @foreach (var sensor in allSensors) { <tr> <td>@(sensor.GetType().Name)</td> <td> @{ if (Check(sensor)) { <b><font color="green">Доступен</font></b> } else { <b><font color="red">Нет доступа</font></b> } } </td> </tr> } </tbody> </table> @code{ List<object> allSensors = [Accelerometer.Default, Compass.Default, Magnetometer.Default, Barometer.Default, Gyroscope.Default, OrientationSensor.Default]; private bool Check(object sensor) { return (bool)(sensor.GetType().GetProperty("IsSupported").GetValue(sensor)); } }
Здесь мы создаем список сенсоров:
List<object> allSensors = [Accelerometer.Default, Compass.Default, Magnetometer.Default, Barometer.Default, Gyroscope.Default, OrientationSensor.Default];
а затем в разметке компонента запускаем цикл, в котором проверяем доступность датчика на устройстве, выводя в качестве имени сенсора имя класса, реализующего интерфейс по умолчанию и состояние датчика:
@foreach (var sensor in allSensors) { <tr> <td>@(sensor.GetType().Name)</td> <td> @{ if (Check(sensor)) { <b><font color="green">Доступен</font></b> } else { <b><font color="red">Нет доступа</font></b> } } </td> </tr> }
В методе Check()
мы, используя рефлексию, запрашиваем значение свойства IsSupported
:
private bool Check(object sensor) { return (bool)(sensor.GetType().GetProperty("IsSupported").GetValue(sensor)); }
Запустим приложение и проверим результат. На моем устройстве Android я получил следующую таблицу:
Теперь рассмотрим работу с конкретным датчиком. Как было сказано выше — принцип работы с датчиками одинаковый, поэтому в качестве примера, рассмотрим работу с акселерометром.
Чтение данных акселерометра
Добавим в код компонента Home
следующие методы:
public void ToggleAccelerometer() { if (Accelerometer.Default.IsSupported) { if (!Accelerometer.Default.IsMonitoring) { Accelerometer.Default.ReadingChanged += ReadingChanged; Accelerometer.Default.Start(SensorSpeed.UI); } else { Accelerometer.Default.Stop(); Accelerometer.Default.ReadingChanged -= ReadingChanged; } } } private void ReadingChanged(object? sender, AccelerometerChangedEventArgs e) { MainThread.BeginInvokeOnMainThread(()=> { accel = $"Показания акселерометра: {e.Reading.ToString()}"; StateHasChanged(); }); }
Метод ToggleAccelerometer()
начинает или останавливает прослушивание датчика. Если датчик доступен и не производится «прослушивание», то мы подписываемся на событие ReadingChanged
и запускаем прослушивание со скоростью UI
.
if (!Accelerometer.Default.IsMonitoring) { Accelerometer.Default.ReadingChanged += ReadingChanged; Accelerometer.Default.Start(SensorSpeed.UI); }
иначе — отписываемся от получения события и останавливаем работу с датчиком:
Accelerometer.Default.Stop(); Accelerometer.Default.ReadingChanged -= ReadingChanged;
Метод ReadingChanged()
— обработчик события. Здесь мы обновляем интерфейс приложения — выводим данные полученные с датчика:
private void ReadingChanged(object? sender, AccelerometerChangedEventArgs e) { accel = $"Показания акселерометра: \r\n {e.Reading.ToString()}"; StateHasChanged(); }
переменная accel
— это обычная строка:
string accel = "";
Теперь добавим новые элементы управления в разметку компонента:
<button class="btn-primary" @onclick="ToggleAccelerometer">Акселерометр</button> <p>@accel</p>
Теперь, если запустить приложение и нажать кнопку «Акселерометр», то можно увидеть показания датчика — ускорение по осям.
Получение сообщения о встряхивании устройства
У датчика Accelerometer
определено также событие
event EventHandler? ShakeDetected;
которое срабатывает при встряхивании устройства. Чтобы им воспользоваться, напишем ещё один обработчик:
string snake = ""; private void ShakeDetected(object? sender, EventArgs e) { MainThread.BeginInvokeOnMainThread(() => { snake = "А-А-А-А-А-!!!!!"; StateHasChanged(); }); }
и подпишемся на событие ShakeDetected
в методе ToggleAccelerometer()
:
public void ToggleAccelerometer() { if (Accelerometer.Default.IsSupported) { if (!Accelerometer.Default.IsMonitoring) { Accelerometer.Default.ReadingChanged += ReadingChanged; Accelerometer.Default.ShakeDetected += ShakeDetected; //подписываемся на событие встряхивания Accelerometer.Default.Start(SensorSpeed.UI); } else { Accelerometer.Default.Stop(); Accelerometer.Default.ShakeDetected += ShakeDetected; //отписываемся Accelerometer.Default.ReadingChanged -= ReadingChanged; } } }
Теперь запустите приложение, включите датчик и потрясите устройство — на экране вы увидите:
Соответственно, чем дольше вы будете трясти устройство, тем длиннее будет строка:
Итого
Все доступные для работы интерфейсы датчиков располагаются в пространстве имен Microsoft.Maui.Devices.Sensors
. Работа с датчиками строится по одному принципу — мы должны проверить доступность датчика, вызвать метод Start(), указав скорость чтения данных с датчика и подписаться на событие обновления данных датчика.