您的位置:首页 > 移动开发 > Android开发

android高分段进阶攻略(2)传感器

2014-03-02 15:51 260 查看
  一开始,先对昨晚在昆明市火车站遇难的同胞表示默哀,并对恶势力进行谴责,你们如果有再大的冤情也不要对平民下手,所谓冤有头债有主,该弄谁弄谁去啊,欺负百姓算是怎么回事,所以在遇到突发情况下,首先要有泰山崩于前而面不改色的镇定,其次要么能像成龙大哥那样以一抵十的身手,要么就是跑得快,第一项技能好像普通人是无法学会的,那我们只能学习第二项技能——跑得快,当然冰冻三尺非一日寒,这就需要大家平时多多锻炼,怎么记录提醒自己锻炼了,就和我们今天要说这个计步器APP有关了。

上次我已经和大家基本介绍了下各种传感器,今天就是传感器的实际应用,由于商业运作的原因,还暂时不能开源我做的app,文章末尾会有上传个pedometer计步器,供大家学习。

首先问下大家觉得计步器应该是用什么传感器了,其实就是利用方向传感器,根据上次说的Value的那个值进行判断,计步器原理就是人拿着手机走,走一步会产生振荡,从而方向传感获得参数Value,通过两次Value[1]的变化值之差来判断人是否走路,从而达到计步效果。核心代码如下:public void onSensorChanged(SensorEvent event)
{
// 当两个values[1]值之差的绝对值大于8时认为走了一步

if (Math.abs(event.values[1] - lastPoint) > 8)
{
lastPoint = event.values[1];
count++;
}
}
然后如何完整的实现这个APP了,首先我们应该构思用户界面上这个功能需要些什么,下图是我设计的主要界面:

界面看起来很复杂,其实很简单,需要一张表记录用户的记录,然后显示出来,点击开始启动service,每一分钟刷新下界面,画出一个心电图,点击结束关闭service。

首先我们来写service,第一个service从最简单刷新界面service开始,这个service很简单,当接收到广播的时候,获得相关参数进行刷新。public class StepUpdateReceiver extends BroadcastReceiver{

public void onReceive(Context context, Intent intent) {

Bundle bundle = intent.getExtras();//获得Bundle

int steps = bundle.getInt("step");//读取步数

view1.stepsPerMin = steps+PerMin;//view1是读取了MainActivity里面的view,PerMin是记录每分钟走了几步

view1.stepsToday = steps+Today;//Today是记录今天走了几步

view1.isMoving = true;//表示用户走路

view1.updateView(); //刷新界面,重画界面

}

}
然后我们来写一个ManagerSerivce,用户通过点击按钮传过来广播消息,通过这个类去判断用户是进行启动还是结束,代码如下:
class ManagerReceiver extends BroadcastReceiver{

public void onReceive(Context context, Intent intent) {

int result = intent.getIntExtra("result");
switch(result){
case WalkingService.CMD_STOP://停止服务
stopSelf();
break;
case WalkingService.CMD_START: //SERVICE启动
isActivityOn = true;
Intent i = new Intent();
i.setAction("MainActivity");i.putExtra("step", steps);
sendBroadcast(i);
break;
}
}
}
写完ManagerService我们开始写最关键的WalkingService:
public class WalkingService extends Service{

SensorManagerSimulator mySensorManager;
WalkingListener wl; //这里自己写了个接听类
int steps=0;
boolean isActivityOn = false; //Activity 是否运行
boolean isServiceOn = false;
NotificationManager nm;//声明NotificationManager
long timeInterval = 60*1000;
final static int CMD_STOP = 0;
final static int CMD_START = 1;
ManagerReceiver receiver; //声明BroadcastReceiver
Handler myHandler = new Handler(){//定时上传数据
public void handleMessage(Message msg) {
uploadData();
super.handleMessage(msg);
}
};
public void onCreate() {
super.onCreate();
wl = new WalkingListener(this); //创建监听器类
//初始化传感器
mySensorManager = SensorManagerSimulator.getSystemService(this, SENSOR_SERVICE);
mySensorManager.connectSimulator();
//注册监听器
mySensorManager.registerListener(wl,SensorManager.SENSOR_ACCELEROMETER,SensorManager.SENSOR_DELAY_UI);
nm = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
}
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
isServiceOn = true;
showNotification();//添加Notification
receiver = new ManagerReceiver();
IntentFilter filter1 = new IntentFilter();
filter1.addAction("WalkingService");
registerReceiver(receiver, filter1);
//每分钟刷新一次界面
if(isServiceOn){
Message msg =myHandler.obtainMessage();
myHandler.sendMessageDelayed(msg,
timeInterval);
}
}
public void onDestroy() {
mySensorManager.unregisterListener(wl);
wl = null;
mySensorManager = null;
nm.cancel(0);
unregisterReceiver(receiver);
super.onDestroy();
}
private void showNotification() {
Intent intent = new Intent(this,WalkingActivity.class);
PendingIntent pi = PendingIntent.getActivity(this,
0, intent, 0);
Notification myNotification = new Notification();
myNotification.icon = R.drawable.icon;
myNotification.defaults = otification.DEFAULT_ALL;
myNotification.setLatestEventInfo(this,
"计步器运行中", "点击查看", pi);
nm.notify(0,myNotification);
}
public void uploadData(){
对数据库进行操作,并发送广播给StepUpdateSerivce
}
}
这里主要有几个重点,第一在oncreate里面初始化传感器,和上一节的方法一致,第二在onstart注册接听器,第三在ondestory方法里面取消接听器,有些细节需要的解释的,什么是NotificatonMangager,这是一个公用类,用于在android通知栏显示app信息和手机状态信息,自己写了一个show方法用于,最小化APP的时候,用户可以在通知栏里面看到该app;为什么不时时刷新,太吃机子性能,用户体验性不好,只能改成每分钟刷新,因为需要画图。
最后我们在把核心代码写在WalkingListener里面就可以了。

public class WalkingListener implements SensorListener

{

WalkingService father; // WalkingService 引用
float [] preCoordinate;
double currentTime=0,lastTime=0; //记录时间
float WALKING_THRESHOLD = 20;
public WalkingListener(WalkingService father){
this.father = father;
}
public void onAccuracyChanged(int arg0, int arg1) {}
//传感器发生变化后调用该方法
public void onSensorChanged(int sensor, float[] values) {
if(sensor ==SensorManager.SENSOR_ACCELEROMETER){
analyseData(values);//调用方法分析数据
}
}
public void analyseData(float[] values){
currentTime=System.currentTimeMillis();
//每隔200MS 取加速度力和前一个进行比较
if(currentTime - lastTime >200){
if(preCoordinate == null){//还未存过数据
preCoordinate = new float[3];
for(int i=0;i<3;i++){
preCoordinate = values;
}  
}
else{ //进行比较  
int angle= calculateAngle(values,preCoordinate);  
if(angle >=WALKING_THRESHOLD){  
father.steps++; //步数增加  
updateData(); //更新步数,并且向walkingService发送消息  
}  
for(int i=0;i<3;i++){  
preCoordinate=values;  
}}  
lastTime = currentTime;//重新计时  
}  
}  
public void updateData(){ 
Intent intent = new Intent(); //创建Intent 对象 
intent.setAction("MainActivity"); 
intent.putExtra("step", father.steps);//添加步数 
father.sendBroadcast(intent); //发出广播 
} 
public int calculateAngle(float[] newPoints,float[] oldPoints){  
int angle=0;  
float vectorProduct=0; //向量积  
float newMold=0; //新向量的模  
float oldMold=0; //旧向量的模  
for(int i=0;i<3;i++){  
vectorProduct +=newPoints*oldPoints;  
newMold += newPoints*newPoints;  
oldMold += oldPoints*oldPoints;  
}  
newMold = (float)Math.sqrt(newMold);  
oldMold = (float)Math.sqrt(oldMold);  
//计算夹角的余弦  
float cosineAngle=(float)(vectorProduct/(newMold*oldMold));  
//通过余弦值求角度  
float fangle = (float)  
Math.toDegrees(Math.acos(cosineAngle));  
angle = (int)fangle;  
return angle; //返回向量的夹角  
}

关于算法,因为需要精确,所以我进行的是向量夹角的判断,当夹角大于20的时候就证明用户走了一步,其实算法多样,你可以自己选择,这也是我百度到的算法,至此一个计步器就完成了。
最后希望大家能踊跃评论,大家可以说下自己想实现什么app,我先去试试,然后做成教程来写出,不然我一个人做过的app也很少,下面是网上开源的demo,我的demo等后续再上传。

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: