您的位置:首页 > 移动开发 > Android开发

android 计步器代码(prdometer)

2016-06-03 17:46 741 查看
应用主要是实现记步功能,可以比较准确的显示出步数。

1、在启动应用的时候先初始化ui和启动线程,在线程里更新步数。然后启动Service。

package com.example.pedometer;

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Handler.Callback;
import android.os.Message;
import android.os.Messenger;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends Activity implements Callback {

private static final String TAG="nsc";
public static final int MSG_FROM_CLIENT = 0;
public static final int MSG_FROM_SERVER = 1;//返回服务
public static final int REQUEST_SERVER = 2;//取消服务
private long TIME_INTERVAL = 500;

private TextView text;
private Handler delayHandler;
private Messenger messenger;
private Messenger mGetReplyMessenger = new Messenger(new Handler(this));

ServiceConnection conn = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub

}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
try{
messenger = new Messenger(service);
Message msg = Message.obtain(null,MSG_FROM_CLIENT);
msg.replyTo = mGetReplyMessenger;//replyTo消息管理器
Log.d(TAG,"msg ="+ msg);
messenger.send(msg);//发送消息出去
}catch(Exception e){
e.printStackTrace();
}
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initUI();//初始化ui和启动线程
setupService();//启动服务
}

/**
* 启动服务
*/
private void setupService() {
// TODO Auto-generated method stub
Intent intent = new Intent(this,StepService.class);
//使用这个ServiceConnection,客户端可以绑定到一个service,通过把它传给bindService()
//第一个bindService()的参数是一个明确指定了要绑定的service的Intent.
//第二个参数是ServiceConnection对象.
//第三个参数是一个标志,它表明绑定中的操作.它一般应是BIND_AUTO_CREATE,这样就会在service不存在时创建一个.其它可选的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,不想指定时设为0即可.。
bindService(intent, conn, BIND_AUTO_CREATE);//BIND_AUTO_CREATE =1
startService(intent);
}

private void initUI() {
// TODO Auto-generated method stub
text = (TextView)findViewById(R.id.text);
delayHandler = new Handler(this);
}

@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
switch(msg.what){
case MSG_FROM_SERVER:
Log.d(TAG,"text="+ msg.getData().getInt("step"));
text.setText(msg.getData().getInt("step")+"");//显示记步数
//延时500ms发送值为REQUEST_SERVER 消息
delayHandler.sendEmptyMessageDelayed(REQUEST_SERVER, TIME_INTERVAL);
break;
case REQUEST_SERVER:
try{
Message message = Message.obtain(null,MSG_FROM_CLIENT);//发送消息
message.replyTo = mGetReplyMessenger;
Log.d(TAG,"message="+ message);
messenger.send(message);
}catch(Exception e){
e.printStackTrace();
}
break;
}
return false;
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unbindService(conn);//解除服务的绑定
}

}
代码布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="@drawable/aa"
tools:context=".MainActivity" >

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:layout_centerInParent="true"
android:textSize="100sp"/>

</RelativeLayout>
2、StepService.java 代码:

package com.example.pedometer;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;

public class StepService extends Service implements SensorEventListener {

private final static String TAG="SetpService";

private SensorManager sensorManager;
private StepDcretor stepDetector;
private BroadcastReceiver mBroadcastReceiver;
private final static int MSG=0;
private final static int MSG_SERVER=1;

//计步器传感器类型 0-counter 1-detector
private static int stepSensor = -1;

private Messenger messenger = new Messenger(new MessenerHandler());
private static class MessenerHandler extends Handler{

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch(msg.what){
case MSG:
try{
Messenger messenger = msg.replyTo;
Message replyMsg = Message.obtain(null, MSG_SERVER);
Bundle bundle = new Bundle();
bundle.putInt("step", StepDcretor.CURRENT_SETP);
replyMsg.setData(bundle);
Log.d(TAG, replyMsg+"");
messenger.send(replyMsg);
}catch(Exception e){
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}

}

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return messenger.getBinder();
}

@Override
@Deprecated
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return START_STICKY;
}

private void startStepDetector(){
if(sensorManager != null && stepDetector !=null){
sensorManager.unregisterListener(stepDetector);
sensorManager = null;
stepDetector = null;
}
//getLock(this);
//获取传感器管理器的实例
sensorManager = (SensorManager)this.getSystemService(SENSOR_SERVICE);
//android 4.4以后可以使用计步传感器  在根据API不同版本分别执行addCountStepListener和addBasePedoListener两个方法
int VERSION_CODES = android.os.Build.VERSION.SDK_INT;
Log.d(TAG, VERSION_CODES+"");
if(VERSION_CODES>19){//sdk版本
addCountStepListener();
}else{
addBasePedoListener();
}
}

private void addBasePedoListener() {
// TODO Auto-generated method stub
stepDetector = new StepDcretor(this);
// 获得传感器的类型,这里获得的类型是加速度传感器
// 此方法用来注册,只有注册过才会生效,参数:SensorEventListener的实例,Sensor的实例,更新速率
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// sensorManager.unregisterListener(stepDetector);
sensorManager.registerListener(stepDetector, sensor,SensorManager.SENSOR_DELAY_UI);
stepDetector.setOnSensorChangeListener(new StepDcretor.OnSensorChangeListener() {

@Override
public void onChange() {
// updateNotification("今日步数:" + StepDcretor.CURRENT_SETP + " 步");
}
});
}

private void addCountStepListener() {
// TODO Auto-generated method stub
//android 两种计步方式 detector启动后,确认了,才启动counter.
Sensor detectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);//计步传感器
Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);//步行检测传感器
if (countSensor != null) {
stepSensor = 0;
Log.v("base", "countSensor");
//第一个参数是Listener,第二个参数是所得传感器类型,第三个参数值获取传感器信息的频率
sensorManager.registerListener(StepService.this, countSensor, SensorManager.SENSOR_DELAY_UI);
} else if (detectorSensor != null) {
stepSensor = 1;
Log.v("base", "detector");
sensorManager.registerListener(StepService.this, detectorSensor, SensorManager.SENSOR_DELAY_UI);
} else {
Log.v("xf", "Count sensor not available!");
addBasePedoListener();
}
}

@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
if(stepSensor ==0){
StepDcretor.CURRENT_SETP = (int)event.values[0];
}else if(stepSensor ==1){
StepDcretor.CURRENT_SETP++;
}
//updateNotification("今日步数:" + StepDcretor.CURRENT_SETP + " 步");
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
//这里开启了一个线程,因为后台服务也是在主线程中进行,这样可以安全点,防止主线程阻塞
new Thread(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
startStepDetector();
}
}).start();

}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
unregisterReceiver(mBroadcastReceiver);//注销广播
Intent intent = new Intent(this,StepService.class);
startService(intent);//重新启动StepService 服务
super.onDestroy();
}

@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}

@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub

}

}
3、StepDcretor.java是记步算法的实现,详细可看代码。

package com.example.pedometer;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.os.CountDownTimer;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

public class StepDcretor implements SensorEventListener {
//存放三轴数据
float[] oriValues = new float[3];
final int valueNum = 4;
//用于存放计算阈值的波峰波谷差值
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;

private final String TAG = "StepDcretor";
// alpha 由 t / (t + dT)计算得来,其中 t 是低通滤波器的时间常数,dT 是事件报送频率
//    private final float alpha = 0.8f;
//    private long perCalTime = 0;
//
//    //最新修改的精度值
//    private final float minValue = 9.8f;
//    private final float maxValue = 9.9f;
//    //9.5f
//    private final float verminValue = 8.5f;
//    //10.0f
//    private final float vermaxValue = 11.5f;
//    private final float minTime = 150;
//    private final float maxTime = 2000;

/**
* 0-准备计时   1-计时中  2-准备为正常计步计时  3-正常计步中
*/
private int CountTimeState = 0;
public static int CURRENT_SETP = 0;
public static int TEMP_STEP = 0;
private int lastStep = -1;
// 加速计的三个维度数值
public static float[] gravity = new float[3];
public static float[] linear_acceleration = new float[3];
//用三个维度算出的平均值
public static float average = 0;

private Timer timer;
// 倒计时4秒,4秒内不会显示计步,用于屏蔽细微波动
private long duration = 4000;
private TimeCount time;

OnSensorChangeListener onSensorChangeListener;

public interface OnSensorChangeListener {
void onChange();
}

public StepDcretor(Context context) {
super();
}

public void onAccuracyChanged(Sensor arg0, int arg1) {

}

public OnSensorChangeListener getOnSensorChangeListener() {
return onSensorChangeListener;
}

public void setOnSensorChangeListener(
OnSensorChangeListener onSensorChangeListener) {
this.onSensorChangeListener = onSensorChangeListener;
}

public void onSensorChanged(SensorEvent event) {
Sensor sensor = event.sensor;
synchronized (this) {
if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
calc_step(event);
}
}
}
/**
* 获取传感器xyz值 然后传入  DetectorNewStep
* @param 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 == 3) {
CURRENT_SETP++;
if (onSensorChangeListener != null) {
onSensorChangeListener.onChange();
}
}
}

/*
* 检测波峰
* 以下四个条件判断为波峰:
* 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;
}

if (!isDirectionUp && lastStatus
&& (continueUpFormerCount >= 2 && (oldValue >= 11.76 && oldValue < 19.6))) {
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)
ave = (float) 4.3;
else if (ave >= 7 && ave < 8)
ave = (float) 3.3;
else if (ave >= 4 && ave < 7)
ave = (float) 2.3;
else if (ave >= 3 && ave < 4)
ave = (float) 2.0;
else {
ave = (float) 1.3;
}
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;
//            CountTimeState = 2;
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, 3000);
CountTimeState = 3;//正常记步
}

@Override
public void onTick(long millisUntilFinished) {
if (lastStep == TEMP_STEP) {
Log.v(TAG, "onTick 计时停止");
time.cancel();
CountTimeState = 0;
lastStep = -1;
TEMP_STEP = 0;
} else {
lastStep = TEMP_STEP;
}
}

}
//废弃的算法
//    private void oldCalStep(SensorEvent event) {
//        // 用低通滤波器分离出重力加速度
//        gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
//        gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
//        gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
//
//        average = (float) Math.sqrt(Math.pow(gravity[0], 2)
//                + Math.pow(gravity[1], 2) + Math.pow(gravity[2], 2));
//
//        if (average <= minValue) {
//            Log.v("xfblog", "低");
//            perCalTime = System.currentTimeMillis();
//        }
//        else if (average >= maxValue) {
//            Log.v("xfblog", "高");
//            float betweentime = System.currentTimeMillis()
//                    - perCalTime;
//            if (betweentime >= minTime && betweentime < maxTime) {
//                perCalTime = 0;
//                if (CountTimeState == 0) {
//                    // 开启计时器
//                    time = new TimeCount(duration, 800);
//                    time.start();
//                    CountTimeState = 1;
//                    Log.v(TAG, "开启计时器");
//                } else if (CountTimeState == 1) {
//                    TEMP_STEP++;
//                    Log.v(TAG, "计步中 TEMP_STEP:" + TEMP_STEP);
//                }
//                else if (CountTimeState == 3) {
//                    CURRENT_SETP++;
//                    if (onSensorChangeListener != null) {
//                        onSensorChangeListener.onChange();
//                    }
//                }
//
//
//            }
//        }
//    }
}


4、权限代码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.pedometer"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-feature android:name="android.hardware.sensor.accelerometer" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.pedometer.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.example.pedometer.StepService"
android:process="com.example.pedometer.step"
android:priority="1000">
<intent-filter >
<!-- 系统启动完成后会调用-->
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.DATE_CHANGED"/>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.intent.action.ACTION_TIME_TICK" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</service>
</application>

</manifest>


此算法为网上看到的,裁剪了部分不需要的代码,代码下载:点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息