Chris Jiang的学习笔记

Take your passion and make it happen
  首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

关于android “shake shake 摇摆 摇摆”的实现与优化

Posted on 2010-09-28 22:40  Chrisplus  阅读(582)  评论(0编辑  收藏  举报

  最近在开发一个基于android操作系统的 播放器, 根据我 抽风一样的 设计理念 “更少,更大的按钮”,在第二次更改UI后, 主界面的按钮 被缩减成 3个: 帮助 按钮 ,播放/暂停 以及 音量控制

  预计这三个按钮还会再一次缩减的,到2个,甚至一个,反正这就是我的“UI设计思想”,我觉得挺好看的。

  删是删了,关键是如何实现 被删按钮的 功能……

  打开文件的这一步,我是使用 "shake"这个动作来实现的,摇摆一下手机,之前编写好的一个 打开文件的activity就会被启动

  在SDK中,google提供了这样一个接口,我们可以使用

  import android.hardware.Sensor;
  import android.hardware.SensorEvent;
  import android.hardware.SensorEventListener;
  import android.hardware.SensorListener;
  import android.hardware.SensorManager;

  看这几个包的名字就可以大体的知道,这与sensor有关

  在我的相关activity实现SensorListener接口

  public class HelloBear extends Activity implements SensorListener

  这里 我得到了一个警告,google不建议你使用这个接口,建议你换另外一个可以实现相同功能的……额~算了,就用这个吧……哈哈

  之后,在oncreate中注册一下下

  SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorMgr.registerListener((SensorListenerthis,SensorManager.SENSOR_ACCELEROMETER,SensorManager.SENSOR_DELAY_GAME);

  根据接口的名称,既然是监听,那就需要对于动作的判断……

  当时在写这一段的时候,借鉴刊载在 javaeye上的 一段,非常抱歉我把作者名字给忘记了……但是大体的实现过程是:

  因为这个接口中,并没有专门用于shake动作的判断,而是仅仅给出了 x y z 的一个三维的矢量,思路是,间隔的测量这个三维的矢量,然后求出一个变化速度~ (定义三方向都有变化速度才叫摇摆),当这个速度达到了某个临界值的时候,动作被触发,我的动作是,intent 到另一个 activity

  其实想到这里,我觉得应该没有什么大问题了,当实现了之后,才发现,一个非常非常严重失误,甚至是错误。

  我们知道,在用户摇摆手机的时候,不可能速度的最大值是你设定的临界值,一般情况是,在到达临界值之后,速度还会增长,如果不加以控制的话,这个动作可能会被连续的执行

  在不加控制的情况下,我试验的结果是:我的intent基本平均要被执行3-5次……

  如何解决这个问题呢?或许我的解决方案没有普适性,因为我并没有 完全基于在一个activity里面解决问题,但是可以供参考~因为我们要做的很多意图都是activity之间切换

  在监听判断时 加入一个boolean 标志 ,常态下为true ,在打开(动作发生)后,置为flase,在(动作打开)的activity被销毁后,再置为true,这里需要用到activityForResult

   如:intent.setClass(HelloBear.this, ChooseBear.class);
      HelloBear.this.startActivityForResult(intent, 0); 

  然后在onActivityResult中置标志为常态

  问题得以解决

  最后,贴一下,实现shake的核心代码~基本和javaeye上的一样,只是进行了上述优化(这个算法本身很简单很直观但是很SB~我希望找到更强大的算法)

   public void onSensorChanged(int sensor,float[] values)
    {
     if (sensor == SensorManager.SENSOR_ACCELEROMETER) { 
     
     long curTime = System.currentTimeMillis(); 
     // 每10毫秒检测一次 
     
     if ((curTime - lastUpdate) > 100) { 
     long diffTime = (curTime - lastUpdate); 
     lastUpdate = curTime; 
      
     x = values[SensorManager.DATA_X]; 
     y = values[SensorManager.DATA_Y]; 
     z = values[SensorManager.DATA_Z]; 
      
     float speed = Math.abs(x+y+z - last_x - last_y - last_z) / diffTime * 10000; 
      
     if (speed > SHAKE_THRESHOLD&& shakable ==true )
     {
     
     Intent intent = new Intent();
  intent.setClass(HelloBear.this, ChooseBear.class);
  HelloBear.this.startActivityForResult(intent, 0);
  shakable = false;
  cancelDelayHide();
  
     } 
     
     last_x = x; 
     last_y = y; 
     last_z = z; 
     }
     
     } 
     }