android 计步器代码(prdometer)
2016-06-03 17:46
741 查看
应用主要是实现记步功能,可以比较准确的显示出步数。
1、在启动应用的时候先初始化ui和启动线程,在线程里更新步数。然后启动Service。
4、权限代码:
此算法为网上看到的,裁剪了部分不需要的代码,代码下载:点击打开链接
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>
此算法为网上看到的,裁剪了部分不需要的代码,代码下载:点击打开链接
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories