You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI中如何获取传感器数据的时间戳?

在.NET MAUI中获取加速度计数据的精确采集时间戳

.NET MAUI的AccelerometerAPI封装未直接提供传感器数据的采集时间戳,AccelerometerData仅包含加速度向量。要获取精确时间,必须通过平台特定代码直接访问原生传感器API——因为原生平台的传感器回调会返回数据采集的原始时间戳,完全避免事件响应延迟带来的误差。

解决方案思路

  1. 在各原生平台项目中实现自定义传感器监听,获取原生传感器返回的时间戳
  2. 将加速度数据和时间戳封装后传递到共享项目
  3. 在共享项目中接收并使用带时间戳的传感器数据

Android平台实现

Android的SensorEvent包含timestamp字段(系统启动以来的纳秒数),可转换为标准DateTime:

// Android项目中创建传感器监听类
using Android.Hardware;
using Microsoft.Maui.ApplicationModel;

public class AndroidAccelerometerListener : Java.Lang.Object, ISensorEventListener
{
    private readonly SensorManager _sensorManager;
    private readonly Sensor _accelerometer;

    public AndroidAccelerometerListener()
    {
        _sensorManager = (SensorManager)Platform.CurrentActivity.GetSystemService(Android.Content.Context.SensorService);
        _accelerometer = _sensorManager.GetDefaultSensor(SensorType.Accelerometer);
    }

    public void StartListening()
    {
        _sensorManager.RegisterListener(this, _accelerometer, SensorDelay.Game);
    }

    public void StopListening()
    {
        _sensorManager.UnregisterListener(this);
    }

    public void OnAccuracyChanged(Sensor sensor, [GeneratedEnum] SensorStatus accuracy)
    {
        // 精度变化处理(可选)
    }

    public void OnSensorChanged(SensorEvent e)
    {
        if (e.Sensor.Type != SensorType.Accelerometer) return;

        // 转换时间戳:系统启动纳秒数转UTC DateTime
        var systemBootTime = DateTimeOffset.UtcNow.AddMilliseconds(-Android.OS.SystemClock.ElapsedRealtime());
        var timestamp = systemBootTime.AddTicks(e.Timestamp / 100); // 纳秒转Ticks

        // 封装数据
        var accelData = new AccelerometerDataWithTime(
            new Vector3(e.Values[0], e.Values[1], e.Values[2]),
            timestamp.UtcDateTime
        );

        // 传递到共享项目
        MessagingCenter.Send(this, "AccelerometerDataReceived", accelData);
    }
}

iOS/macOS平台实现

iOS的CMAccelerometerData包含timestamp字段(设备启动以来的秒数),转换为标准DateTime:

// iOS项目中创建传感器管理类
using CoreMotion;
using Microsoft.Maui.ApplicationModel;

public class iOSAccelerometerManager
{
    private readonly CMMotionManager _motionManager;

    public iOSAccelerometerManager()
    {
        _motionManager = new CMMotionManager();
        _motionManager.AccelerometerUpdateInterval = 1.0 / 60.0; // 60Hz采样率
    }

    public void StartListening()
    {
        if (!_motionManager.AccelerometerAvailable) return;

        _motionManager.StartAccelerometerUpdates(NSOperationQueue.MainQueue, (data, error) =>
        {
            if (data == null) return;

            // 转换时间戳:设备启动秒数转UTC DateTime
            var systemBootTime = DateTimeOffset.UtcNow.AddSeconds(-NSProcessInfo.ProcessInfo.SystemUptime);
            var timestamp = systemBootTime.AddSeconds(data.Timestamp).UtcDateTime;

            // 封装数据
            var accelData = new AccelerometerDataWithTime(
                new Vector3((float)data.Acceleration.X, (float)data.Acceleration.Y, (float)data.Acceleration.Z),
                timestamp
            );

            // 传递到共享项目
            MessagingCenter.Send(this, "AccelerometerDataReceived", accelData);
        });
    }

    public void StopListening()
    {
        _motionManager.StopAccelerometerUpdates();
    }
}

共享项目实现

  1. 创建封装类存储带时间戳的加速度数据:
public class AccelerometerDataWithTime
{
    public Vector3 Acceleration { get; }
    public DateTime Timestamp { get; }

    public AccelerometerDataWithTime(Vector3 acceleration, DateTime timestamp)
    {
        Acceleration = acceleration;
        Timestamp = timestamp;
    }
}
  1. 在页面/ViewModel中订阅数据并使用:
public partial class MainPage : ContentPage
{
    private object _platformListener;

    public MainPage()
    {
        InitializeComponent();
        MessagingCenter.Subscribe<object, AccelerometerDataWithTime>(this, "AccelerometerDataReceived", (sender, data) =>
        {
            // 主线程更新UI
            MainThread.BeginInvokeOnMainThread(() =>
            {
                AccelLabel.TextColor = Colors.Green;
                AccelLabel.Text = $"Accel: {data.Acceleration}\n采集时间: {data.Timestamp:yyyy-MM-dd HH:mm:ss.fff}";
            });
        });
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        // 初始化平台监听
        if (DeviceInfo.Platform == DevicePlatform.Android)
        {
            _platformListener = new AndroidAccelerometerListener();
            ((AndroidAccelerometerListener)_platformListener).StartListening();
        }
        else if (DeviceInfo.Platform is DevicePlatform.iOS or DevicePlatform.MacCatalyst)
        {
            _platformListener = new iOSAccelerometerManager();
            ((iOSAccelerometerManager)_platformListener).StartListening();
        }
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        // 停止监听并取消订阅
        if (_platformListener is AndroidAccelerometerListener androidListener)
        {
            androidListener.StopListening();
        }
        else if (_platformListener is iOSAccelerometerManager iosManager)
        {
            iosManager.StopListening();
        }
        MessagingCenter.Unsubscribe<object, AccelerometerDataWithTime>(this, "AccelerometerDataReceived");
    }
}

关键说明

  • 原生平台的时间戳是传感器硬件采集数据时的系统时间,完全规避了事件响应延迟的问题
  • 时间戳转换需注意不同平台的时间基准:Android是系统启动纳秒数,iOS是设备启动秒数
  • 示例使用MessagingCenter传递数据,也可通过弱事件管理器或依赖注入实现更低耦合的方案

内容的提问来源于stack exchange,提问作者RemeaMiku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 15:45:06