Android 计步传感器的实现

这里写图片描述

在Android4.4之后的版本中,Android在硬件中支持内置计步传感器。例如微信运动,支付宝运动等常用软件都是直接调用了Android中的Sensor传感器服务,从而获取到每日的步数。要完成计步传感器的调用,需要了解Sensor,SensorManager,SensorEventListener,SensorEvent四个类。

Sensor

Sensor即传感器,该类的路径为android.hardware.Sensor。可以使用SensorManager的getSensorList(int)来获取可用的传感器列表。在本文中获取计步传感器是通过SensorManager.getDefaultSensor(int type)来获取的,type主要有两个,分别是TYPE_STEP_DETECTOR和TYPE_STEP_COUNTER。

  • TYPE_STEP_DETECTOR
    用户每迈出一步,此传感器就会触发一个事件。对于每个用户步伐,此传感器提供一个返回值为 1.0 的事件和一个指示此步伐发生时间的时间戳。当用户在行走时,会产生一个加速度上的变化,从而出触发此传感器事件的发生。注意此传感器只能检测到单个有效的步伐,获取单个步伐的有效数据,如果需要统计一段时间内的步伐总数,则需要使用下面的TYPE_STEP_COUNTER传感器。
  • TYPE_STEP_COUNTER
    此传感器会针对检测到的每个步伐触发一个事件,但提供的步数是自设备启动激活该传感器以来累计的总步数,在每次设备重启后会清零,所以务必需要做数据的持久化。该传感器返回一个float的值,100步即100.0,以此类推。该传感器也有一个时间戳成员,记录最后一个步伐的发生事件。该传感器是需要硬件支持的,并且是非常省电的,如果需要长时间获取步伐总数,就不需要解注册该传感器,注册该传感器会一直在后台运行计步。请务必在应用程序中保持注册该传感器,否则该传感器不会被激活从而不会统计总部署。
  • 这两个计步传感器都需要依赖硬件,可以使用PackageManager的hasSystemFeature(String name)方法来检测硬件是否支持该传感器,这两个传感器对应的常量为FEATURE_SENSOR_STEP_DETECTOR 和 FEATURE_SENSOR_STEP_COUNTER 。

    getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)
    getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR)

    注意:这两个计步传感器提供的结果并非总是相同,与来自 TYPE_STEP_DETECTOR 的事件相比,TYPE_STEP_COUNTER 事件的发生延迟时间更长,但这是因为 TYPE_STEP_COUNTER 算法会进行较多的处理以消除误报。因此,TYPE_STEP_COUNTER 在传输事件时可能较为缓慢,但其结果应更为准确。

    SensorManager

    SensorManager是一个系统服务,如果需要获取某个传感器Sensor,则需要通过该系统服务来获取。如果需要获取该系统服务,可以通过Context.getSystemService()方法来获取:

    sensorManager= (SensorManager) getSystemService(SENSOR_SERVICE);

    注意当不需要使用传感器或者应用程序进入后台时,需要手动关闭传感器,如果不及时关闭这些传感器是非常耗电的。当关闭屏幕时系统也不会自动帮你关闭传感器。

    例如下面代码时获取加速度传感器的Demo,当应用程序在前台时使用registerListener来激活传感器,当应用程序退出前台时使用unregisterListener来关闭传感器:

     public class SensorActivity extends Activity implements SensorEventListener {
         private final SensorManager mSensorManager;
         private final Sensor mAccelerometer;
    
         public SensorActivity() {
             mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
             mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
         }
    
         protected void onResume() {
             super.onResume();
             mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
         }
    
         protected void onPause() {
             super.onPause();
             mSensorManager.unregisterListener(this);
         }
    
         public void onAccuracyChanged(Sensor sensor, int accuracy) {
         }
    
         public void onSensorChanged(SensorEvent event) {
         }
     }
    

    SensorEventListener

    SensorEventListener顾名思义就是一个传感器事件的监听器,当在系统服务SensorManager中注册传感器时需要提供一个传感器事件监听器来获取传感器发生的事件,该监听器只有两个需要实现的方法,即onAccuracyChanged(Sensor sensor, int accuracy)和onSensorChanged(SensorEvent event)。

  • onAccuracyChanged(Sensor sensor, int accuracy)
    当注册的传感器的精确度发生变化时会触发该方法
  • onSensorChanged(SensorEvent event)
    当注册的传感器发生新事件时会触发该方法
  • SensorEvent

    SensorEvent即传感器事件,包括了传感器的名字,类型,事件发生时间戳,精确度和传感器数据等信息。

  • accuracy
    精确度信息
  • sensor
    触发该事件的传感器
  • timestamp
    事件发生的时间戳,有19位,需要除以1000000才能获取到Unix时间戳
  • values
    values是一个数组,对应不同的传感器类型,该数组的长度和内容都是不一样的,例如可以是values[0]代表x轴,values[1]代表y轴,values[2]代表z轴等数据。在本文中,计步传感器只需要使用values[0]即可获取到步伐数据。
  • 代码实现

    public class MainActivity extends BaseActivity {
        private TextView stepDetectorText;
        private TextView stepCounterText;
        private TextView stepDetectorTimeText;
        private TextView isSupportStepDetector;
        private TextView isSupportStepCounter;
        private SensorManager sensorManager;
        private Sensor stepCounter;//步伐总数传感器
        private Sensor stepDetector;//单次步伐传感器
        private SensorEventListener stepCounterListener;//步伐总数传感器事件监听器
        private SensorEventListener stepDetectorListener;//单次步伐传感器事件监听器
    
        private SimpleDateFormat simpleDateFormat;//时间格式化
    
        @Override
        protected void initView() {
            setContentView(R.layout.activity_main);
            stepDetectorText= (TextView) findViewById(R.id.StepDetector);
            stepCounterText= (TextView) findViewById(R.id.StepCounter);
            stepDetectorTimeText= (TextView) findViewById(R.id.StepDetectorTime);
            isSupportStepDetector= (TextView) findViewById(R.id.IsSupportStepDetector);
            isSupportStepCounter= (TextView) findViewById(R.id.IsSupportStepCounter);
        }
    
        @Override
        protected void initData() {
            sensorManager= (SensorManager) getSystemService(SENSOR_SERVICE);//获取传感器系统服务
            stepCounter=sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);//获取计步总数传感器
            stepDetector=sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);//获取单次计步传感器
    
            isSupportStepCounter.setText("是否支持StepCounter:"+
                    String.valueOf(getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)));
            isSupportStepDetector.setText("是否支持StepDetector:"+
                    String.valueOf(getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR)));
    
            simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        }
    
        @Override
        protected void initListener() {
            stepCounterListener=new SensorEventListener() {
                @Override
                public void onSensorChanged(SensorEvent event) {
                    Log.e("Counter-SensorChanged",event.values[0]+"---"+event.accuracy+"---"+event.timestamp);
                    stepCounterText.setText("总步伐计数:"+event.values[0]);
                }
    
                @Override
                public void onAccuracyChanged(Sensor sensor, int accuracy) {
                    Log.e("Counter-Accuracy",sensor.getName()+"---"+accuracy);
    
                }
            };
    
            stepDetectorListener=new SensorEventListener() {
                @Override
                public void onSensorChanged(SensorEvent event) {
                    Log.e("Detector-SensorChanged",event.values[0]+"---"+event.accuracy+"---"+event.timestamp);
                    stepDetectorText.setText("当前步伐计数:"+event.values[0]);
                    stepDetectorTimeText.setText("当前步伐时间:"+simpleDateFormat.format(event.timestamp/1000000));
                }
    
                @Override
                public void onAccuracyChanged(Sensor sensor, int accuracy) {
                    Log.e("Detector-Accuracy",sensor.getName()+"---"+accuracy);
    
                }
            };
        }
    
        private void registerSensor(){
            //注册传感器事件监听器
            if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)&&
                    getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR)){
                sensorManager.registerListener(stepDetectorListener,stepDetector,SensorManager.SENSOR_DELAY_FASTEST);
                sensorManager.registerListener(stepCounterListener,stepCounter,SensorManager.SENSOR_DELAY_FASTEST);
            }
        }
    
        private void unregisterSensor(){
            //解注册传感器事件监听器
            if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)&&
                    getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR)){
                sensorManager.unregisterListener(stepCounterListener);
                sensorManager.unregisterListener(stepDetectorListener);
            }
        }
    
        @Override
        public void onPause(){
            super.onPause();
            unregisterSensor();
        }
    
        @Override
        public void onResume(){
            super.onResume();
            registerSensor();
        }
    
    }
    

    注意:

  • 如果需要一直计步则不需要在onPause方法中解注册,可以在应用程序的Application中的onCreate中注册计步传感器stepCounter,stepDetector是单次计步没什么用处,可以忽略,只需要启动stepCounter传感器即可获取步伐总数。
  • 计步器数据会在手机重启后清零,因此需要根据需求做数据保存持久化。
  • 只有注册传感器事件监听器才会激活相应的传感器开始运作,因此需要先注册传感器事件监听器
  • 参考:
    https://developer.android.com/about/versions/android-4.4.html?hl=zh-cn#Animations

  • 5
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
你可以使用 Kotlin 和 Android 中的计步传感器 API 来实现每天计步的功能。以下是一个简单的实现步骤: 1. 在 AndroidManifest.xml 中添加计步传感器权限: ```xml <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> ``` 2. 在 build.gradle 文件中添加计步传感器依赖项: ```groovy dependencies { implementation 'com.google.android.gms:play-services-fitness-ktx:20.0.0' } ``` 3. 在 MainActivity.kt 中实现计步器逻辑: ```kotlin import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.fitness.Fitness import com.google.android.gms.fitness.data.DataType import com.google.android.gms.fitness.request.DataReadRequest import com.google.android.gms.fitness.request.SensorRequest import com.google.android.gms.fitness.result.DataReadResponse import kotlinx.android.synthetic.main.activity_main.* import java.text.SimpleDateFormat import java.util.* import java.util.concurrent.TimeUnit class MainActivity : AppCompatActivity() { private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 获取 Google 帐号 val account = GoogleSignIn.getAccountForExtension(this, Fitness.SENSORS_API) // 注册计步传感器 Fitness.getSensorsClient(this, account) .add( SensorRequest.Builder() .setDataType(DataType.TYPE_STEP_COUNT_DELTA) .setSamplingRate(1, TimeUnit.SECONDS) .build(), null ) .addOnSuccessListener { // 计步传感器注册成功,开始读取步数数据 readStepCountData(account) } .addOnFailureListener { e -> // 计步传感器注册失败 stepCountTextView.text = "Failed to register step sensor: $e" } } private fun readStepCountData(account: GoogleSignInAccount) { // 构造读取步数数据的请求 val today = Date() val endTime = today.time val startTime = dateFormat.parse(dateFormat.format(today))!!.time val request = DataReadRequest.Builder() .read(DataType.TYPE_STEP_COUNT_DELTA) .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS) .build() // 发送读取步数数据的请求 Fitness.getHistoryClient(this, account) .readData(request) .addOnSuccessListener { response -> // 处理读取到的步数数据 handleStepCountData(response) } .addOnFailureListener { e -> // 读取步数数据失败 stepCountTextView.text = "Failed to read step count data: $e" } } private fun handleStepCountData(response: DataReadResponse) { var totalSteps = 0 for (dataSet in response.getDataSets()) { for (dataPoint in dataSet.getDataPoints()) { totalSteps += dataPoint.getValue(Field.FIELD_STEPS).asInt() } } stepCountTextView.text = "Today's steps: $totalSteps" } } ``` 通过上述代码,你可以实现一个简单的每天计步的功能。当你打开应用时,它将自动注册计步传感器并读取当天的步数数据,并将其显示在界面上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值