文档章节

基于Android的计步器(Pedometer)的讲解(四)——后台记步

andyhe91
 andyhe91
发布于 2015/06/27 14:49
字数 1497
阅读 1384
收藏 21
  • 基于Android的计步器(Pedometer)的讲解(四)——后台记步

  • 2015-01-07      58 个评论    来源:a296777513的专栏   

  • 收藏    我要投稿

  • 今天先不说Pedometer(计步器)项目UI方面的了,今天讲一个基于重力加速度的记步功能传感器(Sensor),然后

    在后台开启记步。

     

    计步器(Pedometer)整个项目的源代码,感兴趣的朋友可以下载来看看(记得帮小弟在github打个星~)

     

    先上几张效果图:(效果和上一篇讲到的CircleBar非常的相似,因为记步功能在后台)

    \\

    如图所示,能根据你的一些基本参数,来记步。有一个缺点,因为这个是根据感应加速度来计算是否走一步,所以你在原地晃手机,也会记步,不过正常的走路还是挺准确的。

    首先给出StepDetector类的代码:

     

    ?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    package com.example.histogram.widet;
     
    import android.content.Context;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;
     
    /**
      * 这是一个实现了信号监听的记步的类
      * 这是从谷歌找来的一个记步的算法,看不太懂
      * @author Liyachao Date:2015-1-6
      *
      */
    public class StepDetector implements SensorEventListener {
     
         public static int CURRENT_SETP = 0 ;
         public static float SENSITIVITY = 10 ; // SENSITIVITY灵敏度
         private float mLastValues[] = new float [ 3 * 2 ];
         private float mScale[] = new float [ 2 ];
         private float mYOffset;
         private static long end = 0 ;
         private static long start = 0 ;
         /**
          * 最后加速度方向
          */
         private float mLastDirections[] = new float [ 3 * 2 ];
         private float mLastExtremes[][] = { new float [ 3 * 2 ], new float [ 3 * 2 ] };
         private float mLastDiff[] = new float [ 3 * 2 ];
         private int mLastMatch = - 1 ;
     
         /**
          * 传入上下文的构造函数
          *
          * @param context
          */
         public StepDetector(Context context) {
             super ();
             int h = 480 ;
             mYOffset = h * 0 .5f;
             mScale[ 0 ] = -(h * 0 .5f * ( 1 .0f / (SensorManager.STANDARD_GRAVITY * 2 )));
             mScale[ 1 ] = -(h * 0 .5f * ( 1 .0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
         }
     
         //当传感器检测到的数值发生变化时就会调用这个方法
         public void onSensorChanged(SensorEvent event) {
             Sensor sensor = event.sensor;
             synchronized ( this ) {
                 if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
     
                     float vSum = 0 ;
                     for ( int i = 0 ; i < 3 ; i++) {
                         final float v = mYOffset + event.values[i] * mScale[ 1 ];
                         vSum += v;
                     }
                     int k = 0 ;
                     float v = vSum / 3 ;
     
                     float direction = (v > mLastValues[k] ? 1
                             : (v < mLastValues[k] ? - 1 : 0 ));
                     if (direction == -mLastDirections[k]) {
                         // Direction changed
                         int extType = (direction > 0 ? 0 : 1 ); // minumum or
                                                                 // maximum?
                         mLastExtremes[extType][k] = mLastValues[k];
                         float diff = Math.abs(mLastExtremes[extType][k]
                                 - mLastExtremes[ 1 - extType][k]);
     
                         if (diff > SENSITIVITY) {
                             boolean isAlmostAsLargeAsPrevious = diff > (mLastDiff[k] * 2 / 3 );
                             boolean isPreviousLargeEnough = mLastDiff[k] > (diff / 3 );
                             boolean isNotContra = (mLastMatch != 1 - extType);
     
                             if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough
                                     && isNotContra) {
                                 end = System.currentTimeMillis();
                                 if (end - start > 500 ) { // 此时判断为走了一步
     
                                     CURRENT_SETP++;
                                     mLastMatch = extType;
                                     start = end;
                                 }
                             } else {
                                 mLastMatch = - 1 ;
                             }
                         }
                         mLastDiff[k] = diff;
                     }
                     mLastDirections[k] = direction;
                     mLastValues[k] = v;
                 }
     
             }
         }
         //当传感器的经度发生变化时就会调用这个方法,在这里没有用
         public void onAccuracyChanged(Sensor arg0, int arg1) {
     
         }
     
    }


    下来是后台服务StepService的代码:

     

     

    ?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    package com.example.histogram.widet;
     
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.hardware.Sensor;
    import android.hardware.SensorManager;
    import android.os.IBinder;
     
    public class StepService extends Service {
         public static Boolean flag = false ;
         private SensorManager sensorManager;
         private StepDetector stepDetector;
     
         @Override
         public IBinder onBind(Intent arg0) {
             // TODO Auto-generated method stub
             return null ;
         }
     
         @Override
         public void onCreate() {
             super .onCreate();
             //这里开启了一个线程,因为后台服务也是在主线程中进行,这样可以安全点,防止主线程阻塞
             new Thread( new Runnable() {
                 public void run() {
                     startStepDetector();
                 }
             }).start();
     
         }
     
         private void startStepDetector() {
             flag = true ;
             stepDetector = new StepDetector( this );
             sensorManager = (SensorManager) this .getSystemService(SENSOR_SERVICE); //获取传感器管理器的实例
             Sensor sensor = sensorManager
                     .getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //获得传感器的类型,这里获得的类型是加速度传感器
             //此方法用来注册,只有注册过才会生效,参数:SensorEventListener的实例,Sensor的实例,更新速率
             sensorManager.registerListener(stepDetector, sensor,
                     SensorManager.SENSOR_DELAY_FASTEST);
         }
     
         @Override
         public int onStartCommand(Intent intent, int flags, int startId) {
             return super .onStartCommand(intent, flags, startId);
         }
     
         @Override
         public void onDestroy() {
             super .onDestroy();
             flag = false ;
             if (stepDetector != null ) {
                 sensorManager.unregisterListener(stepDetector);
             }
     
         }
    }


    最后把FragmentPedometer测试页面的代码也给大家,如果大家看过之前的博客,应该知道这是一个碎片。如果没看过,看兴趣的朋友可以看看之前的博文:

     

     

    ?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    package com.example.histogram;
     
    import java.text.SimpleDateFormat;
    import java.util.Date;
     
     
     
     
     
     
    import com.example.changepage1.R;
    import com.example.histogram.widet.CircleBar;
    import com.example.histogram.widet.StepDetector;
    import com.example.histogram.widet.StepService;
    import com.example.histogram.widet.Weather;
     
     
     
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.View.OnClickListener;
     
    /**
      * 这是记步的碎片
      * Author: 李垭超   email:296777513@qq.com
      * Date: 2015-1-6
      * Time: 下午8:39
      */
    public class FragmentPedometer extends Fragment implements OnClickListener{
         private View view;
         private CircleBar circleBar;
         private int total_step = 0 ;
         private Thread thread;
         private int Type = 1 ;
         private int calories = 0 ;
         private int step_length = 50 ;
         private int weight = 70 ;
         private Weather weather;
         private String test;
         private boolean flag = true ; // 来判断第三个页面是否开启动画
     
         @SuppressLint (HandlerLeak)
         Handler handler = new Handler() {
             public void handleMessage(Message msg) {
                 super .handleMessage(msg);
                 total_step = StepDetector.CURRENT_SETP;
                 if (Type == 1 ) {
                     circleBar.setProgress(total_step, Type);
                 } else if (Type == 2 ) {
                     calories = ( int ) (weight * total_step * step_length * 0.01 * 0.01 );
                     circleBar.setProgress(calories, Type);
                 } else if (Type == 3 ) {
                     if (flag) {
                         circleBar.startCustomAnimation();
                         flag = false ;
                     }
                     if (test != null || weather.getWeather() == null ) {
                         weather.setWeather(正在更新中...);
                         weather.setPtime();
                         weather.setTemp1();
                         weather.setTemp2();
                         circleBar.startCustomAnimation();
                         circleBar.setWeather(weather);
                     } else {
                         circleBar.setWeather(weather);
                     }
     
                 }
     
             }
     
         };
     
     
         @Override
         public View onCreateView(LayoutInflater inflater, ViewGroup container,
                 Bundle savedInstanceState) {
             view = inflater.inflate(R.layout.pedometer, container, false );
             init();
             mThread();
             return view;
         }
         private void init() {      
             Intent intent = new Intent(getActivity(), StepService. class );
             getActivity().startService(intent);
             weather = new Weather();
             circleBar = (CircleBar) view.findViewById(R.id.progress_pedometer);
             circleBar.setMax( 10000 );
             circleBar.setProgress(StepDetector.CURRENT_SETP, 1 );
             circleBar.startCustomAnimation();
             circleBar.setOnClickListener( this );
     
         }
         
         private void mThread() {
             if (thread == null ) {
     
                 thread = new Thread( new Runnable() {
                     public void run() {
                         while ( true ) {
                             try {
                                 Thread.sleep( 500 );
                             } catch (InterruptedException e) {
                                 e.printStackTrace();
                             }
                             if (StepService.flag) {
                                 Message msg = new Message();
                                 handler.sendMessage(msg);
                             }
                         }
                     }
                 });
                 thread.start();
             }
         }
         @Override
         public void onClick(View v) {
             switch (v.getId()) {
             case R.id.progress_pedometer:
                 if (Type == 1 ) {
                     Type = 2 ;
                 } else if (Type == 2 ) {
                     flag = true ;
                     Type = 3 ;
                 } else if (Type == 3 ) {
                     Type = 1 ;
                 }
                 Message msg = new Message();
                 handler.sendMessage(msg);
                 break ;
             default :
                 break ;
             }
             
         }
     
    }


    © 著作权归作者所有

    共有 人打赏支持
    andyhe91
    粉丝 58
    博文 129
    码字总数 209109
    作品 0
    长沙
    加载中

    评论(1)

    orangebook
    orangebook
    嗯!不错,就是计步关键代码能,算法分析出来就好了
    Android 计步器应用 - healthgo

    healthgo a android pedometer app (安卓计步器) Support Android 4.1- 7.0 Thanks Project/People desc other Realm a mobile database 使用了这个数据库 EventBus a publish/subscribe eve......

    五十风
    04/13
    0
    0
    超酷的计步器APP(一)——炫酷功能实现,自定义水波纹特效、自定义炫酷开始按钮、属性动画的综合体验

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52976877 超酷的计步器APP(一)——炫酷功能实现,自定义水波纹特效、自定义炫酷开...

    Aduroidpc
    2016/10/31
    0
    0
    Android开发者必须深入学习的10个应用开源项目

    Android开发又将带来新一轮热潮,很多开发者都投入到这个浪潮中去了,创造了许许多 多相当优秀的应用。其中也有许许多多的开发者提供了应用开源项 目,贡献出他们的智 慧和创造力。 Android开...

    破晓之星
    2012/04/29
    0
    40
    Android计步模块优化(今日步数)

    最近在项目中研究计步模块,主要功能记录当天步数,类似微信运动,支付宝计步,咕咚今日步数。 开发之前的调研工作,搜遍baidu,google,github都没有找到我想要的demo和文章,大多数都是需要...

    jiahongfei
    2017/10/20
    0
    5
    android-pedometer

    一款开源软件,计算步数、计算消耗能量,还支持语音播报。 通过设置可以选择中文语音,建议用讯飞的。 github的下载地址:https://github.com/bagilevi/android-pedometer 作者主页:https:/...

    Airship
    2015/03/12
    0
    0

    没有更多内容

    加载失败,请刷新页面

    加载更多

    linux 系统的运行级别

    运行级别 运行级别 | 含义 0 关机 1 单用户模式,可以想象为windows 的安全模式,主要用于修复系统 2 不完全的命令模式,不含NFS服务 3 完全的命令行模式,就是标准的字符界面 4 系统保留 5 ...

    Linux学习笔记
    今天
    2
    0
    学习设计模式——命令模式

    任何模式的出现,都是为了解决一些特定的场景的耦合问题,以达到对修改封闭,对扩展开放的效果。命令模式也不例外: 命令模式是为了解决命令的请求者和命令的实现者之间的耦合关系。 解决了这...

    江左煤郎
    今天
    3
    0
    字典树收集(非线程安全,后续做线程安全改进)

    将500W个单词放进一个数据结构进行存储,然后进行快速比对,判断一个单词是不是这个500W单词之中的;来了一个单词前缀,给出500w个单词中有多少个单词是该前缀. 1、这个需求首先需要设计好数据结...

    算法之名
    昨天
    15
    0
    GRASP设计模式

    此文参考了这篇博客,建议读者阅读原文。 面向对象(Object-Oriented,OO)是当下软件开发的主流方法。在OO分析与设计中,我们首先从问题领域中抽象出领域模型,在领域模型中以适当的粒度归纳...

    克虏伯
    昨天
    1
    0
    Coding and Paper Letter(四十)

    资源整理。 1 Coding: 1.Tomislav Hengl撰写的非官方作者指南:Michael Gould•Wouter Gerritsma。 UnofficialGuide4Authors 2.R语言包rwrfhydro,社区贡献的工具箱,用于管理,分析和可视化...

    胖胖雕
    昨天
    1
    0

    没有更多内容

    加载失败,请刷新页面

    加载更多

    返回顶部
    顶部