最近要实现一个手机摇晃的功能。
想到这个功能可能应用广泛,比如摇晃手机换图片、截图、洗牌、结束当前程序等,所以找了些资料,并加以改进,将此功能封装成类(ShakeDetector),方便今后使用。
摇晃检测基于加速传感器(Sensor.TYPE_ACCELEROMETER)。
由于重力的存在,当手机静止放于桌面时,加速传感器也是有加速度的。所以,仅通过是否有加速度来判断摇晃是不行的。
那么,判断加速度的变化吧。在一个较短的时间间隔求出加速度的差值,跟一个指定的阈值比较,如果差值大于阈值,则认为是摇晃发生了。ClingMarks的方法将x、y、z方向的加速度差值简单的加起来,我认为不是很准确。
加速度是向量,求差应该是各方向的差值平方后相加,再开方。(数学忘光了,应该没记错吧。)
所以就有了这行代码:
1
|
float
delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / diffTime *
10000
;
|
功能封装成类ShakeDetector,实现了SensorEventListener接口,用于向系统注册传感器事件的Listener。
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
|
package
zhengzhiren.android.hardware;
import
java.util.ArrayList;
import
android.content.Context;
import
android.hardware.Sensor;
import
android.hardware.SensorEvent;
import
android.hardware.SensorEventListener;
import
android.hardware.SensorManager;
import
android.util.FloatMath;
/**
* 用于检测手机晃动
*
* @author 郑智仁
*/
public
class
ShakeDetector
implements
SensorEventListener {
/**
* 检测的时间间隔
*/
static
final
int
UPDATE_INTERVAL =
100
;
/**
* 上一次检测的时间
*/
long
mLastUpdateTime;
/**
* 上一次检测时,加速度在x、y、z方向上的分量,用于和当前加速度比较求差。
*/
float
mLastX, mLastY, mLastZ;
Context mContext;
SensorManager mSensorManager;
ArrayList<OnShakeListener> mListeners;
/**
* 摇晃检测阈值,决定了对摇晃的敏感程度,越小越敏感。
*/
public
int
shakeThreshold =
5000
;
public
ShakeDetector(Context context) {
mContext = context;
mSensorManager = (SensorManager) context
.getSystemService(Context.SENSOR_SERVICE);
mListeners =
new
ArrayList<OnShakeListener>();
}
/**
* 当摇晃事件发生时,接收通知
*/
public
interface
OnShakeListener {
/**
* 当手机晃动时被调用
*/
void
onShake();
}
/**
* 注册OnShakeListener,当摇晃时接收通知
*
* @param listener
*/
public
void
registerOnShakeListener(OnShakeListener listener) {
if
(mListeners.contains(listener))
return
;
mListeners.add(listener);
}
/**
* 移除已经注册的OnShakeListener
*
* @param listener
*/
public
void
unregisterOnShakeListener(OnShakeListener listener) {
mListeners.remove(listener);
}
/**
* 启动摇晃检测
*/
public
void
start() {
if
(mSensorManager ==
null
) {
throw
new
UnsupportedOperationException();
}
Sensor sensor = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if
(sensor ==
null
) {
throw
new
UnsupportedOperationException();
}
boolean
success = mSensorManager.registerListener(
this
, sensor,
SensorManager.SENSOR_DELAY_GAME);
if
(!success) {
throw
new
UnsupportedOperationException();
}
}
/**
* 停止摇晃检测
*/
public
void
stop() {
if
(mSensorManager !=
null
)
mSensorManager.unregisterListener(
this
);
}
@Override
public
void
onAccuracyChanged(Sensor sensor,
int
accuracy) {
// TODO Auto-generated method stub
}
@Override
public
void
onSensorChanged(SensorEvent event) {
long
currentTime = System.currentTimeMillis();
long
diffTime = currentTime - mLastUpdateTime;
if
(diffTime < UPDATE_INTERVAL)
return
;
mLastUpdateTime = currentTime;
float
x = event.values[
0
];
float
y = event.values[
1
];
float
z = event.values[
2
];
float
deltaX = x - mLastX;
float
deltaY = y - mLastY;
float
deltaZ = z - mLastZ;
mLastX = x;
mLastY = y;
mLastZ = z;
float
delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ
* deltaZ)
/ diffTime *
10000
;
if
(delta > shakeThreshold) {
// 当加速度的差值大于指定的阈值,认为这是一个摇晃
this
.notifyListeners();
}
}
/**
* 当摇晃事件发生时,通知所有的listener
*/
private
void
notifyListeners() {
for
(OnShakeListener listener : mListeners) {
listener.onShake();
}
}
}
|
如何使用ShakeDetector
1、new一个ShakeDetector
2、调用mShakeDetector.registerOnShakeListener()注册一个OnShakeListener
3、在OnShakeListener的onShake函数中,处理摇晃事件
4、调用mShakeDetector.start()启动摇晃检测
5、mShakeDetector.stop()用于停止摇晃检测
参考资料:
http://www.clingmarks.com/?p=25
http://android.hlidskialf.com/blog/code/android-shake-detection-listener
注:此文转载