Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 1644|回复: 0

Android 计步

[复制链接]

697

主题

1142

帖子

4086

积分

认证用户组

Rank: 5Rank: 5

积分
4086
发表于 2018-7-27 18:25:36 | 显示全部楼层 |阅读模式
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/ab ... hl=zh-cn#Animations





回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|firemail ( 粤ICP备15085507号-1 )

GMT+8, 2024-3-29 09:22 , Processed in 0.084453 second(s), 20 queries .

Powered by Discuz! X3

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表