基于Android的计步器(Pedometer)的讲解(四)——后台记步 – Android移动开发技术文章_手机开发 – 红黑联盟

今天先不说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
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;
        }
        
    }
}

这些是主要的代码,其他次要的我就不贴出来了,如果想要demo的朋友可以在下面留言,我给你们。

如果大家有什么建议,可以提出来哦。

相关文章:

基于Android的计步器(Pedometer)的讲解(一)——Fragment页面跳转 – Android移动开发技术文章_手机开发 – 红黑联盟

基于Android的计步器(Pedometer)的讲解(二)——柱状图分析 – Android移动开发技术文章_手机开发 – 红黑联盟

基于Android的计步器(Pedometer)的讲解—ExpandableListView – Android移动开发技术文章_手机开发 – 红黑联盟

基于Android的计步器(Pedometer)的讲解(四)——后台记步 – Android移动开发技术文章_手机开发 – 红黑联盟

基于Android的计步器(Pedometer)的讲解(五)——跟随界面滑动的指示器 – Android移动开发技术文章_手机开发 – 红黑联盟

 

 

来源URL:http://www.2cto.com/kf/201501/367660.html?WebShieldDRSessionVerify=wWHXSJoEf5OWH5AkVgjI