基於Android的計步器(Pedometer)的講解(四)——後臺記步php
今天先不說Pedometer(計步器)項目UI方面的了,今天講一個基於重力加速度的記步功能傳感器(Sensor),而後android
在後臺開啓記步。git
計步器(Pedometer)整個項目的源代碼,感興趣的朋友能夠下載來看看(記得幫小弟在github打個星~)github
先上幾張效果圖:(效果和上一篇講到的CircleBar很是的類似,由於記步功能在後臺)算法
如圖所示,能根據你的一些基本參數,來記步。有一個缺點,由於這個是根據感應加速度來計算是否走一步,因此你在原地晃手機,也會記步,不過正常的走路仍是挺準確的。安全
首先給出StepDetector類的代碼:app
?dom
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
137
138
139
140
141
142
143
144
|
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
;
}
}
}
|