Содержание
Современные устройства на базе 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(), указав скорость чтения данных с датчика и подписаться на событие обновления данных датчика.


