• 热门专题

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

作者:  发布日期:2014-03-03 21:15:17
Tag标签:Android  分段  进阶  
  • 一开始,先对昨晚在昆明市火车站遇难的同胞表示默哀,并对恶势力进行谴责,你们如果有再大的冤情也不要对平民下手,所谓冤有头债有主,该弄谁弄谁去啊,欺负百姓算是怎么回事,所以在遇到突发情况下,首先要有泰山崩于前而面不改色的镇定,其次要么能像成龙大哥那样以一抵十的身手,要么就是跑得快,第一项技能好像普通人是无法学会的,那我们只能学习第二项技能——跑得快,当然冰冻三尺非一日寒,这就需要大家平时多多锻炼,怎么记录提醒自己锻炼了,就和我们今天要说这个计步器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的时候就证明用户走了一步,其实算法多样,你可以自己选择,这也是我百度到的算法,至此一个计步器就完成了。

     

     

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规