欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android计步功能的实现代码

程序员文章站 2023-12-10 12:06:04
本文对原文计步项目进行了精简,移除了进程服务和计时、守护进程、数据库保存等等,方便扩展功能。 android4.4以上版本,有些手机有计步传感器可以直接使用, 而有些手机...

本文对原文计步项目进行了精简,移除了进程服务和计时、守护进程、数据库保存等等,方便扩展功能。

android4.4以上版本,有些手机有计步传感器可以直接使用, 而有些手机没有,但有加速度传感器,也可以实现计步功能(需要计算加速度波峰波谷来判断人走一步)!

一.使用

public class mainactivity extends appcompatactivity implements stepcallback{
 .........
 @override
 public void step(int stepnum) {
  // 计步回调
  steptext.settext("步数:" + stepnum);
 }

 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);  
  setcontentview(r.layout.activity_main);
  steptext = (textview) findviewbyid(r.id.step_text);

  // 开启计步监听, 分为加速度传感器、或计步传感器
  stepsensor = new stepsensorpedometer(this, this);
  if (!stepsensor.registerstep()) {
   toast.maketext(this, "计步传传感器不可用!", toast.length_short).show();
   stepsensor = new stepsensoracceleration(this, this);
   if (!stepsensor.registerstep()) {
    toast.maketext(this, "加速度传感器不可用!", toast.length_short).show();
   }
  }
 }
 .......
 }

二.计步传感器抽象类

/**
 * 计步传感器抽象类, 子类分为加速度传感器、或计步传感器
 */
public abstract class stepsensorbase implements sensoreventlistener {
 private context context;
 public stepcallback stepcallback;
 public sensormanager sensormanager;
 public static int current_setp = 0;
 public boolean isavailable = false;

 public stepsensorbase(context context, stepcallback stepcallback) {
  this.context = context;
  this.stepcallback = stepcallback;
 }

 /**
  * 开启计步
  */
 public boolean registerstep() {
  if (sensormanager != null) {
   sensormanager.unregisterlistener(this);
   sensormanager = null;
  }
  sensormanager = (sensormanager) context.getsystemservice(context.sensor_service);
  registersteplistener();
  return isavailable;
 }

 /**
  * 注册计步监听器
  */
 protected abstract void registersteplistener();

 /**
  * 注销计步监听器
  */
 public abstract void unregisterstep();
}

三.直接使用计步传感器

/**
 * 计步传感器
 */
public class stepsensorpedometer extends stepsensorbase {
 private final string tag = "stepsensorpedometer";
 private int laststep = -1;
 private int livestep = 0;
 private int increment = 0;
 private int sensormode = 0; // 计步传感器类型

 public stepsensorpedometer(context context, stepcallback stepcallback) {
  super(context, stepcallback);
 }

 @override
 protected void registersteplistener() {
  sensor detectorsensor = sensormanager.getdefaultsensor(sensor.type_step_detector);
  sensor countsensor = sensormanager.getdefaultsensor(sensor.type_step_counter);
  if (sensormanager.registerlistener(this, detectorsensor, sensormanager.sensor_delay_ui)) {
   isavailable = true;
   sensormode = 0;
   log.i(tag, "计步传感器detector可用!");
  } else if (sensormanager.registerlistener(this, countsensor, sensormanager.sensor_delay_ui)) {
   isavailable = true;
   sensormode = 1;
   log.i(tag, "计步传感器counter可用!");
  } else {
   isavailable = false;
   log.i(tag, "计步传感器不可用!");
  }
 }

 @override
 public void unregisterstep() {
  sensormanager.unregisterlistener(this);
 }

 @override
 public void onsensorchanged(sensorevent event) {
  livestep = (int) event.values[0];
  if (sensormode == 0) {
   stepsensorbase.current_setp += livestep;
  } else if (sensormode == 1) {
   stepsensorbase.current_setp = livestep;
  }
  stepcallback.step(stepsensorbase.current_setp);
 }

 @override
 public void onaccuracychanged(sensor sensor, int accuracy) {
 }
}

三.使用加速度传感器实现计步功能

public class stepsensoracceleration extends stepsensorbase {
 private final string tag = "stepsensoracceleration";
 //存放三轴数据
 final int valuenum = 5;
 //用于存放计算阈值的波峰波谷差值
 float[] tempvalue = new float[valuenum];
 int tempcount = 0;
 //是否上升的标志位
 boolean isdirectionup = false;
 //持续上升次数
 int continueupcount = 0;
 //上一点的持续上升的次数,为了记录波峰的上升次数
 int continueupformercount = 0;
 //上一点的状态,上升还是下降
 boolean laststatus = false;
 //波峰值
 float peakofwave = 0;
 //波谷值
 float valleyofwave = 0;
 //此次波峰的时间
 long timeofthispeak = 0;
 //上次波峰的时间
 long timeoflastpeak = 0;
 //当前的时间
 long timeofnow = 0;
 //当前传感器的值
 float gravitynew = 0;
 //上次传感器的值
 float gravityold = 0;
 //动态阈值需要动态的数据,这个值用于这些动态数据的阈值
 final float initialvalue = (float) 1.7;
 //初始阈值
 float threadvalue = (float) 2.0;

 //初始范围
 float minvalue = 11f;
 float maxvalue = 19.6f;

 /**
  * 0-准备计时 1-计时中 2-正常计步中
  */
 private int counttimestate = 0;
 public static int temp_step = 0;
 private int laststep = -1;
 //用x、y、z轴三个维度算出的平均值
 public static float average = 0;
 private timer timer;
 // 倒计时3.5秒,3.5秒内不会显示计步,用于屏蔽细微波动
 private long duration = 3500;
 private timecount time;

 public stepsensoracceleration(context context, stepcallback stepcallback) {
  super(context, stepcallback);
 }

 @override
 protected void registersteplistener() {
  // 注册加速度传感器
  isavailable = sensormanager.registerlistener(this,
    sensormanager.getdefaultsensor(sensor.type_accelerometer),
    sensormanager.sensor_delay_ui);
  if (isavailable) {
   log.i(tag, "加速度传感器可用!");
  } else {
   log.i(tag, "加速度传感器不可用!");
  }
 }

 @override
 public void unregisterstep() {
  sensormanager.unregisterlistener(this);
 }

 public void onaccuracychanged(sensor arg0, int arg1) {
 }

 public void onsensorchanged(sensorevent event) {
  sensor sensor = event.sensor;
  synchronized (this) {
   if (sensor.gettype() == sensor.type_accelerometer) {
    calc_step(event);
   }
  }
 }

 synchronized private void calc_step(sensorevent event) {
  average = (float) math.sqrt(math.pow(event.values[0], 2)
    + math.pow(event.values[1], 2) + math.pow(event.values[2], 2));
  detectornewstep(average);
 }

 /*
  * 检测步子,并开始计步
  * 1.传入sersor中的数据
  * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步
  * 3.符合时间差条件,波峰波谷差值大于initialvalue,则将该差值纳入阈值的计算中
  * */
 public void detectornewstep(float values) {
  if (gravityold == 0) {
   gravityold = values;
  } else {
   if (detectorpeak(values, gravityold)) {
    timeoflastpeak = timeofthispeak;
    timeofnow = system.currenttimemillis();

    if (timeofnow - timeoflastpeak >= 200
      && (peakofwave - valleyofwave >= threadvalue) && (timeofnow - timeoflastpeak) <= 2000) {
     timeofthispeak = timeofnow;
     //更新界面的处理,不涉及到算法
     prestep();
    }
    if (timeofnow - timeoflastpeak >= 200
      && (peakofwave - valleyofwave >= initialvalue)) {
     timeofthispeak = timeofnow;
     threadvalue = peak_valley_thread(peakofwave - valleyofwave);
    }
   }
  }
  gravityold = values;
 }

 private void prestep() {
//  if (counttimestate == 0) {
//   // 开启计时器
//   time = new timecount(duration, 700);
//   time.start();
//   counttimestate = 1;
//   log.v(tag, "开启计时器");
//  } else if (counttimestate == 1) {
//   temp_step++;
//   log.v(tag, "计步中 temp_step:" + temp_step);
//  } else if (counttimestate == 2) {
  current_setp++;
//   if (stepcallback != null) {
  stepcallback.step(current_setp);
//   }
//  }

 }


 /*
  * 检测波峰
  * 以下四个条件判断为波峰:
  * 1.目前点为下降的趋势:isdirectionup为false
  * 2.之前的点为上升的趋势:laststatus为true
  * 3.到波峰为止,持续上升大于等于2次
  * 4.波峰值大于1.2g,小于2g
  * 记录波谷值
  * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值
  * 2.所以要记录每次的波谷值,为了和下次的波峰做对比
  * */
 public boolean detectorpeak(float newvalue, float oldvalue) {
  laststatus = isdirectionup;
  if (newvalue >= oldvalue) {
   isdirectionup = true;
   continueupcount++;
  } else {
   continueupformercount = continueupcount;
   continueupcount = 0;
   isdirectionup = false;
  }

//  log.v(tag, "oldvalue:" + oldvalue);
  if (!isdirectionup && laststatus
    && (continueupformercount >= 2 && (oldvalue >= minvalue && oldvalue < maxvalue))) {
   peakofwave = oldvalue;
   return true;
  } else if (!laststatus && isdirectionup) {
   valleyofwave = oldvalue;
   return false;
  } else {
   return false;
  }
 }

 /*
  * 阈值的计算
  * 1.通过波峰波谷的差值计算阈值
  * 2.记录4个值,存入tempvalue[]数组中
  * 3.在将数组传入函数averagevalue中计算阈值
  * */
 public float peak_valley_thread(float value) {
  float tempthread = threadvalue;
  if (tempcount < valuenum) {
   tempvalue[tempcount] = value;
   tempcount++;
  } else {
   tempthread = averagevalue(tempvalue, valuenum);
   for (int i = 1; i < valuenum; i++) {
    tempvalue[i - 1] = tempvalue[i];
   }
   tempvalue[valuenum - 1] = value;
  }
  return tempthread;

 }

 /*
  * 梯度化阈值
  * 1.计算数组的均值
  * 2.通过均值将阈值梯度化在一个范围里
  * */
 public float averagevalue(float value[], int n) {
  float ave = 0;
  for (int i = 0; i < n; i++) {
   ave += value[i];
  }
  ave = ave / valuenum;
  if (ave >= 8) {
//   log.v(tag, "超过8");
   ave = (float) 4.3;
  } else if (ave >= 7 && ave < 8) {
//   log.v(tag, "7-8");
   ave = (float) 3.3;
  } else if (ave >= 4 && ave < 7) {
//   log.v(tag, "4-7");
   ave = (float) 2.3;
  } else if (ave >= 3 && ave < 4) {
//   log.v(tag, "3-4");
   ave = (float) 2.0;
  } else {
//   log.v(tag, "else");
   ave = (float) 1.7;
  }
  return ave;
 }

 class timecount extends countdowntimer {
  public timecount(long millisinfuture, long countdowninterval) {
   super(millisinfuture, countdowninterval);
  }

  @override
  public void onfinish() {
   // 如果计时器正常结束,则开始计步
   time.cancel();
   current_setp += temp_step;
   laststep = -1;
   log.v(tag, "计时正常结束");

   timer = new timer(true);
   timertask task = new timertask() {
    public void run() {
     if (laststep == current_setp) {
      timer.cancel();
      counttimestate = 0;
      laststep = -1;
      temp_step = 0;
      log.v(tag, "停止计步:" + current_setp);
     } else {
      laststep = current_setp;
     }
    }
   };
   timer.schedule(task, 0, 2000);
   counttimestate = 2;
  }

  @override
  public void ontick(long millisuntilfinished) {
   if (laststep == temp_step) {
    log.v(tag, "ontick 计时停止:" + temp_step);
    time.cancel();
    counttimestate = 0;
    laststep = -1;
    temp_step = 0;
   } else {
    laststep = temp_step;
   }
  }
 }
}


本文源码:steporient_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。