android 计步器代码(prdometer)

应用主要是实现记步功能,可以比较准确的显示出步数。

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>

此算法为网上看到的,裁剪了部分不需要的代码,代码下载:点击打开链接


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值