AChartEngine是一个很强大的图表引擎,我在上学的时候就接触过,并且利用它做了一个传感器的应用,想想现在也很久远了,今天就把这个app的源码贴出来供其他人研究这款引擎。
app的效果如下:
g ithub项目地址: https://github.com/AlexZhuo/SensorMonitor
此APP的主要特性如下:
1、支持手机传感器数量探测,支持加速度,磁场,距离等传感器数据的实时获取
2、使用了一些github上的第三方控件来美化UI,
3、支持全屏显示
4、通过旧版的xUtils 2实现了数据库实时记录
5、通过POI来将数据库的数据导出为excel,方便以后分析。
AChartEngine根据事先准备好的数据进行绘图,也就是说是一帧一帧的进行绘制,如果我们想动态生成波浪图并让坐标轴随之移动其实也不难,只需要隔一段时间在旧数据上添加数据并刷新一下view即可。
想要在项目中使用这个图标引擎,AChartEngine的jar包的下载地址:
http://repository-achartengine.forge.cloudbees.com/snapshot/org/achartengine/achartengine/1.2.0/
注意版本,以后说不定还会出新版。
下面把控制绘图的代码贴一下,原理其实不是很复杂,github上有全部app的代码,如果你喜欢也可以在原来基础上帮我完善一下(学生时代第一个上线项目,想想还有点小激动)。
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
|
import
java
.
util
.
List
;
import
org
.
achartengine
.
ChartFactory
;
import
org
.
achartengine
.
GraphicalView
;
import
org
.
achartengine
.
chart
.
PointStyle
;
import
org
.
achartengine
.
model
.
XYMultipleSeriesDataset
;
import
org
.
achartengine
.
model
.
XYSeries
;
import
org
.
achartengine
.
renderer
.
XYMultipleSeriesRenderer
;
import
org
.
achartengine
.
renderer
.
XYSeriesRenderer
;
import
android
.
app
.
Activity
;
import
android
.
content
.
Context
;
import
android
.
content
.
Intent
;
import
android
.
graphics
.
Color
;
import
android
.
graphics
.
Paint
.
Align
;
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
.
Message
;
import
android
.
os
.
Vibrator
;
import
android
.
view
.
ViewGroup
.
LayoutParams
;
import
android
.
widget
.
LinearLayout
;
import
android
.
widget
.
TextView
;
import
com
.
lidroid
.
xutils
.
DbUtils
;
import
com
.
lidroid
.
xutils
.
db
.
sqlite
.
Selector
;
import
com
.
lidroid
.
xutils
.
exception
.
DbException
;
import
com
.
situ
.
model
.
Accelerate_info
;
public
class
AccelActivity
extends
Activity
{
public
SensorManager
sensorManager
;
public
Sensor
accelSensor
;
TextView
xText
;
TextView
yText
;
TextView
zText
;
TextView
sumText
;
TextView
danWei
;
TextView
title
;
private
Vibrator
vibrator
;
SensorEventListener
threeParamListener
;
SensorEventListener
oneParamListener
;
SensorEventListener
twoParamListener
;
Handler
avgHandler
;
Thread
avgThread
;
int
sensor_id
=
0
;
//图表相关
private
XYSeries
series
;
private
XYMultipleSeriesDataset
mDataset
;
private
GraphicalView
chart
;
private
XYMultipleSeriesRenderer
renderer
;
private
Context
context
;
private
int
yMax
=
20
;
//y轴最大值,根据不同传感器变化
private
int
xMax
=
100
;
//一屏显示测量次数
@
Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
)
;
setContentView
(
R
.
layout
.
activity_accel
)
;
sensorManager
=
(
SensorManager
)
getSystemService
(
SENSOR_SERVICE
)
;
avgHandler
=
new
AveHandler
(
)
;
//给控件实例化
if
(
xText
==
null
)
{
findViews
(
)
;
}
Intent
intent
=
getIntent
(
)
;
avgThread
=
new
Thread
(
runnable
)
;
//定期更新平均值的线程启动
avgThread
.
start
(
)
;
//初始化各个监听器
initListeners
(
)
;
switch
(
wtd
)
{
case
Sensor
.
TYPE_ACCELEROMETER
:
title
.
setText
(
"加速度传感器"
)
;
danWei
.
setText
(
"N/M^2"
)
;
accelSensor
=
sensorManager
.
getDefaultSensor
(
Sensor
.
TYPE_ACCELEROMETER
)
;
sensorManager
.
registerListener
(
threeParamListener
,
accelSensor
,
sensorManager
.
SENSOR_DELAY_UI
)
;
yMax
=
20
;
sensor_id
=
1
;
break
;
default
:
break
;
}
//初始化图表
initChart
(
"*0.5s"
,
danWei
.
getText
(
)
.
toString
(
)
,
0
,
xMax
,
0
,
yMax
)
;
}
/**
* 抓取view中文本控件的函数
*/
private
void
findViews
(
)
{
xText
=
(
TextView
)
findViewById
(
R
.
id
.
xAxis
)
;
yText
=
(
TextView
)
findViewById
(
R
.
id
.
yAxis
)
;
zText
=
(
TextView
)
findViewById
(
R
.
id
.
zAxis
)
;
sumText
=
(
TextView
)
findViewById
(
R
.
id
.
sum
)
;
danWei
=
(
TextView
)
findViewById
(
R
.
id
.
danWei
)
;
title
=
(
TextView
)
findViewById
(
R
.
id
.
title
)
;
}
/**
* 初始化各类监听器
*/
private
void
initListeners
(
)
{
threeParamListener
=
new
SensorEventListener
(
)
{
//有三个返回参数的监听器
@
Override
public
void
onSensorChanged
(
SensorEvent
event
)
{
// TODO Auto-generated method stub
xText
.
setText
(
event
.
values
[
0
]
+
""
)
;
yText
.
setText
(
event
.
values
[
1
]
+
""
)
;
zText
.
setText
(
event
.
values
[
2
]
+
""
)
;
double
sum
=
threeDimenToOne
(
event
.
values
[
0
]
,
event
.
values
[
1
]
,
event
.
values
[
2
]
)
;
giveAverage
(
sum
)
;
//将当前测量的结果写入buffer,然后定期求buffer里面的平均值,并显示
}
@
Override
public
void
onAccuracyChanged
(
Sensor
sensor
,
int
accuracy
)
{
// TODO Auto-generated method stub
}
}
;
}
/**
* 初始化图表
*/
private
void
initChart
(
String
xTitle
,
String
yTitle
,
int
minX
,
int
maxX
,
int
minY
,
int
maxY
)
{
//这里获得main界面上的布局,下面会把图表画在这个布局里面
LinearLayout
layout
=
(
LinearLayout
)
findViewById
(
R
.
id
.
chart
)
;
//这个类用来放置曲线上的所有点,是一个点的集合,根据这些点画出曲线
series
=
new
XYSeries
(
"历史曲线"
)
;
//创建一个数据集的实例,这个数据集将被用来创建图表
mDataset
=
new
XYMultipleSeriesDataset
(
)
;
//将点集添加到这个数据集中
mDataset
.
addSeries
(
series
)
;
//以下都是曲线的样式和属性等等的设置,renderer相当于一个用来给图表做渲染的句柄
int
lineColor
=
Color
.
BLACK
;
PointStyle
style
=
PointStyle
.
CIRCLE
;
renderer
=
buildRenderer
(
lineColor
,
style
,
true
)
;
//设置好图表的样式
setChartSettings
(
renderer
,
xTitle
,
yTitle
,
minX
,
maxX
,
//x轴最小最大值
minY
,
maxY
,
//y轴最小最大值
Color
.
BLACK
,
//坐标轴颜色
Color
.
WHITE
//标签颜色
)
;
//生成图表
chart
=
ChartFactory
.
getLineChartView
(
this
,
mDataset
,
renderer
)
;
//将图表添加到布局中去
layout
.
addView
(
chart
,
new
LayoutParams
(
LayoutParams
.
FILL_PARENT
,
LayoutParams
.
FILL_PARENT
)
)
;
}
@
Override
protected
void
onDestroy
(
)
{
// TODO Auto-generated method stub
super
.
onDestroy
(
)
;
if
(
threeParamListener
!=
null
)
{
sensorManager
.
unregisterListener
(
threeParamListener
)
;
}
if
(
oneParamListener
!=
null
)
{
sensorManager
.
unregisterListener
(
oneParamListener
)
;
}
if
(
avgThread
!=
null
)
avgThread
.
interrupt
(
)
;
DbUtils
db
=
DbUtils
.
create
(
getApplicationContext
(
)
)
;
//xUtils框架
try
{
List
<
Accelerate_info
>
list
=
db
.
findAll
(
Selector
.
from
(
Accelerate_info
.
class
)
.
where
(
"sensor"
,
"="
,
sensor_id
)
)
;
//看看一共写入了数据库多少数据
System
.
out
.
println
(
"数量是"
+
list
.
size
(
)
)
;
}
catch
(
DbException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
(
)
;
}
}
/**
* 根据三个坐标向量求和向量的模
* @param x
* @param y
* @param z
* @return
*/
public
static
double
threeDimenToOne
(
double
x
,
double
y
,
double
z
)
{
return
Math
.
sqrt
(
x*
x
+
y*
y
+
z*
z
)
;
}
public
int
index
=
0
;
//指示这段时间一共写入了多少个数据
//在这里可以设置缓冲区的长度,用于求平均数
double
[
]
buffer
=
new
double
[
500
]
;
//半秒钟最多放500个数
public
int
INTERVAL
=
500
;
//每半秒求一次平均值
public
double
AVERAGE
=
0
;
//存储平均值
/**
* 一个子线程,没隔固定时间计算这段时间的平均值,并给textView赋值
*/
Runnable
runnable
=
new
Runnable
(
)
{
@
Override
public
void
run
(
)
{
// TODO Auto-generated method stub
System
.
out
.
println
(
"线程已经启动"
)
;
while
(
true
)
{
try
{
Thread
.
sleep
(
INTERVAL
)
;
//没隔固定时间求平均数
}
catch
(
InterruptedException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
(
)
;
avgThread
=
new
Thread
(
runnable
)
;
avgThread
.
start
(
)
;
}
if
(
index
!=
0
)
{
double
sum
=
0
;
for
(
int
i
=
0
;
i
<
index
;
i
++
)
{
sum
+=
buffer
[
i
]
;
}
AVERAGE
=
sum
/
new
Double
(
index
)
;
index
=
0
;
//让下标恢复
}
avgHandler
.
sendEmptyMessage
(
1
)
;
//提示handler更新ui
}
}
}
;
/**
* 更新平均值的显示值
*/
public
void
setAverageView
(
)
{
//更新textView
if
(
sumText
==
null
)
return
;
sumText
.
setText
(
AVERAGE
+
""
)
;
}
/**
* 每隔固定时间给平均值赋值,并且更新图表的操作
* @author love fang
*
*/
class
AveHandler
extends
Handler
{
@
Override
public
void
handleMessage
(
Message
msg
)
{
// TODO Auto-generated method stub
setAverageView
(
)
;
//显示平均值
updateChart
(
)
;
//更新图表
//把当前值存入数据库
DbUtils
db
=
DbUtils
.
create
(
getApplicationContext
(
)
)
;
Accelerate_info
accelerate_info
=
new
Accelerate_info
(
System
.
currentTimeMillis
(
)
,
AVERAGE
,
sensor_id
)
;
try
{
db
.
save
(
accelerate_info
)
;
//将当前平均值存入数据库
}
catch
(
DbException
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
(
)
;
System
.
out
.
println
(
"保存失败"
)
;
}
}
}
/**
* 接受当前传感器的测量值,存到缓存区中去,并将下标加一
* @param data
*/
public
void
giveAverage
(
double
data
)
{
buffer
[
index
]
=
data
;
index
++
;
}
/**
*设置图表曲线样式
**/
protected
XYMultipleSeriesRenderer
buildRenderer
(
int
color
,
PointStyle
style
,
boolean
fill
)
{
XYMultipleSeriesRenderer
renderer
=
new
XYMultipleSeriesRenderer
(
)
;
//设置图表中曲线本身的样式,包括颜色、点的大小以及线的粗细等
XYSeriesRenderer
r
=
new
XYSeriesRenderer
(
)
;
r
.
setColor
(
color
)
;
r
.
setPointStyle
(
style
)
;
r
.
setFillPoints
(
fill
)
;
r
.
setLineWidth
(
2
)
;
//这是线宽
renderer
.
addSeriesRenderer
(
r
)
;
return
renderer
;
}
/**
* 初始化图表
* @param renderer
* @param xTitle
* @param yTitle
* @param xMin
* @param xMax
* @param yMin
* @param yMax
* @param axesColor
* @param labelsColor
*/
protected
void
setChartSettings
(
XYMultipleSeriesRenderer
renderer
,
String
xTitle
,
String
yTitle
,
double
xMin
,
double
xMax
,
double
yMin
,
double
yMax
,
int
axesColor
,
int
labelsColor
)
{
//有关对图表的渲染可参看api文档
renderer
.
setChartTitle
(
title
.
getText
(
)
.
toString
(
)
)
;
//设置标题
renderer
.
setXAxisMin
(
xMin
)
;
//设置x轴的起始点
renderer
.
setXAxisMax
(
xMax
)
;
//设置一屏有多少个点
renderer
.
setYAxisMin
(
yMin
)
;
renderer
.
setYAxisMax
(
yMax
)
;
renderer
.
setBackgroundColor
(
Color
.
BLACK
)
;
renderer
.
setLabelsColor
(
Color
.
YELLOW
)
;
renderer
.
setAxesColor
(
axesColor
)
;
renderer
.
setLabelsColor
(
labelsColor
)
;
renderer
.
setShowGrid
(
true
)
;
renderer
.
setGridColor
(
Color
.
BLUE
)
;
//设置格子的颜色
renderer
.
setXLabels
(
20
)
;
//没有什么卵用
renderer
.
setYLabels
(
20
)
;
//把y轴刻度平均分成多少个
renderer
.
setXTitle
(
xTitle
)
;
//x轴的标题
renderer
.
setYTitle
(
yTitle
)
;
//y轴的标题
renderer
.
setYLabelsAlign
(
Align
.
RIGHT
)
;
renderer
.
setPointSize
(
(
float
)
2
)
;
renderer
.
setShowLegend
(
false
)
;
}
int
[
]
xv
=
new
int
[
1000
]
;
//用来显示的数据
double
[
]
yv
=
new
double
[
1000
]
;
private
int
addX
=
-
1
;
private
double
addY
=
0
;
/**
* 更新图表的函数,其实就是重绘
*/
private
void
updateChart
(
)
{
//设置好下一个需要增加的节点
addY
=
AVERAGE
;
//需要增加的值
//移除数据集中旧的点集
mDataset
.
removeSeries
(
series
)
;
//判断当前点集中到底有多少点,因为屏幕总共只能容纳100个,所以当点数超过100时,长度永远是100
//每一个新点坐标都后移一位
series
.
add
(
addX
++
,
addY
)
;
//最重要的一句话,以xy对的方式往里放值
if
(
addX
>
100
)
{
//如果超出了屏幕边界,实现坐标轴自动移动的方法
renderer
.
setXAxisMin
(
addX
-
100
)
;
//显示范围为100
renderer
.
setXAxisMax
(
addX
)
;
}
//重要:在数据集中添加新的点集
mDataset
.
addSeries
(
series
)
;
//视图更新,没有这一步,曲线不会呈现动态
//如果在非UI主线程中,需要调用postInvalidate(),具体参考api
chart
.
invalidate
(
)
;
}
}
|