我需要添加一个摇功能,将刷新我的Android应用程序。

我所找到的所有文档都涉及实现SensorListener,但Eclipse告诉我它已被弃用,并建议使用SensorEventListener。

有人知道如何创建这个震动控制器吗?


当前回答

下面是一个示例代码。 把这些放到你的活动课上:

  /* put this into your activity class */
  private SensorManager mSensorManager;
  private float mAccel; // acceleration apart from gravity
  private float mAccelCurrent; // current acceleration including gravity
  private float mAccelLast; // last acceleration including gravity

  private final SensorEventListener mSensorListener = new SensorEventListener() {

    public void onSensorChanged(SensorEvent se) {
      float x = se.values[0];
      float y = se.values[1];
      float z = se.values[2];
      mAccelLast = mAccelCurrent;
      mAccelCurrent = (float) Math.sqrt((double) (x*x + y*y + z*z));
      float delta = mAccelCurrent - mAccelLast;
      mAccel = mAccel * 0.9f + delta; // perform low-cut filter
    }

    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
  };

  @Override
  protected void onResume() {
    super.onResume();
    mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
  }

  @Override
  protected void onPause() {
    mSensorManager.unregisterListener(mSensorListener);
    super.onPause();
  }

把这个添加到你的onCreate方法中:

    /* do this in onCreate */
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
    mAccel = 0.00f;
    mAccelCurrent = SensorManager.GRAVITY_EARTH;
    mAccelLast = SensorManager.GRAVITY_EARTH;

然后你可以在你的应用程序中任何你想要的地方询问“mAccel”当前加速度,独立于轴,并从静态加速度(如重力)中清除。 大概是。如果没有移动,则为0,如果设备震动,则为>2。

根据评论-测试这一点:

if (mAccel > 12) {
    Toast toast = Toast.makeText(getApplicationContext(), "Device has shaken.", Toast.LENGTH_LONG);
    toast.show();
}

注:

The accelometer should be deactivated onPause and activated onResume to save resources (CPU, Battery). The code assumes we are on planet Earth ;-) and initializes the acceleration to earth gravity. Otherwise you would get a strong "shake" when the application starts and "hits" the ground from free-fall. However, the code gets used to the gravitation due to the low-cut filter and would work also on other planets or in free space, once it is initialized. (you never know how long your application will be in use...;-)

其他回答

Shaker.java

    import java.util.ArrayList;
    import android.content.Context;
    import android.hardware.Sensor;
    import android.hardware.SensorEvent;
    import android.hardware.SensorEventListener;
    import android.hardware.SensorManager;

    public class Shaker implements SensorEventListener{

        private static final String SENSOR_SERVICE = Context.SENSOR_SERVICE;
        private SensorManager sensorMgr;
        private Sensor mAccelerometer;
        private boolean accelSupported;
        private long timeInMillis;
        private long threshold;
        private OnShakerTreshold listener;
        ArrayList<Float> valueStack;

        public Shaker(Context context, OnShakerTreshold listener, long timeInMillis, long threshold) {
            try {
                this.timeInMillis = timeInMillis;
                this.threshold = threshold;
                this.listener = listener;
                if (timeInMillis<100){
                    throw new Exception("timeInMillis < 100ms");
                }
                valueStack = new ArrayList<Float>((int)(timeInMillis/100));
                sensorMgr = (SensorManager) context.getSystemService(SENSOR_SERVICE);
                mAccelerometer = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

            } catch (Exception e){
                e.printStackTrace();
            }
        }

        public void start() {
            try {
                accelSupported = sensorMgr.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); 
                if (!accelSupported) {
                    stop();
                    throw new Exception("Sensor is not supported");
                }
            } catch (Exception e){
                e.printStackTrace();
            }
        }

        public void stop(){
            try {
                sensorMgr.unregisterListener(this, mAccelerometer);
            } catch (Exception e){
                e.printStackTrace();
            }
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                stop();
            } catch (Exception e){
                e.printStackTrace();
            }
            super.finalize();
        }

        long lastUpdate = 0;
        private float last_x;
        private float last_y;
        private float last_z;

public void onSensorChanged(SensorEvent event) {
    try {
        if (event.sensor == mAccelerometer) {
            long curTime = System.currentTimeMillis();
            if ((curTime-lastUpdate)>getNumberOfMeasures()){

                lastUpdate = System.currentTimeMillis();
                float[] values = event.values;
                if (valueStack.size()>(int)getNumberOfMeasures())
                    valueStack.remove(0);
                float x = (int)(values[SensorManager.DATA_X]);
                float y = (int)(values[SensorManager.DATA_Y]);
                float z = (int)(values[SensorManager.DATA_Z]);
                float speed = Math.abs((x+y+z) - (last_x + last_y + last_z));

                valueStack.add(speed);

                String posText = String.format("X:%4.0f Y:%4.0f Z:%4.0f", (x-last_x), (y-last_y), (z-last_z));

                last_x = (x);
                last_y = (y);
                last_z = (z);

                float sumOfValues = 0;
                float avgOfValues = 0;

                for (float f : valueStack){
                        sumOfValues = (sumOfValues+f);
                }
                avgOfValues = sumOfValues/(int)getNumberOfMeasures();

                if (avgOfValues>=threshold){
                    listener.onTreshold();
                    valueStack.clear();
                }

                System.out.println(String.format("M: %+4d A: %5.0f V: %4.0f %s", valueStack.size(),avgOfValues,speed,posText));

            }
        }
    } catch (Exception e){
        e.printStackTrace();
    }
}


        private long getNumberOfMeasures() {
            return timeInMillis/100;
        }

        public void onAccuracyChanged(Sensor sensor, int accuracy) {}

        public interface OnShakerTreshold {
            public void onTreshold();
        }
    }

MainActivity.java

public class MainActivity extends Activity implements OnShakerTreshold{


    private Shaker s;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        s = new Shaker(getApplicationContext(), this, 5000, 20);
        // 5000 = 5 second of shaking
        // 20 = minimal threshold (very angry shaking :D)
        // beware screen rotation reset counter
    }

    @Override
    protected void onResume() {
        s.start();
        super.onResume();
    }

    @Override
    protected void onPause() {
        s.stop();
        super.onPause();
    }

    public void onTreshold() {
        System.out.println("FIRE LISTENER");
        RingtoneManager.getRingtone(getApplicationContext(), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)).play();
    }


}

玩得开心。

package anywheresoftware.b4a.student;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;

public class ShakeEventListener implements SensorEventListener {

    /*
     * The gForce that is necessary to register as shake.
     * Must be greater than 1G (one earth gravity unit).
     * You can install "G-Force", by Blake La Pierre
     * from the Google Play Store and run it to see how
     *  many G's it takes to register a shake
     */
    private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
    private static int SHAKE_SLOP_TIME_MS = 500;
    private static final int SHAKE_COUNT_RESET_TIME_MS = 1000;

    private OnShakeListener mListener;
    private long mShakeTimestamp;
    private int mShakeCount;

    public void setOnShakeListener(OnShakeListener listener) {
        this.mListener = listener;
    }

    public interface OnShakeListener {
        public void onShake(int count);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // ignore
    }

    @Override
    public void onSensorChanged(SensorEvent event) {

        if (mListener != null) {
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];

            float gX = x / SensorManager.GRAVITY_EARTH;
            float gY = y / SensorManager.GRAVITY_EARTH;
            float gZ = z / SensorManager.GRAVITY_EARTH;

            // gForce will be close to 1 when there is no movement.
            float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);

            if (gForce > SHAKE_THRESHOLD_GRAVITY) {
                final long now = System.currentTimeMillis();
                // ignore shake events too close to each other (500ms)
                if (mShakeTimestamp + getSHAKE_SLOP_TIME_MS() > now) {
                    return;
                }

                // reset the shake count after 3 seconds of no shakes
                if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
                    mShakeCount = 0;
                }

                mShakeTimestamp = now;
                mShakeCount++;

                mListener.onShake(mShakeCount);
            }
        }
    }

    private long getSHAKE_SLOP_TIME_MS() {
        // TODO Auto-generated method stub
        return SHAKE_SLOP_TIME_MS;
    }

    public void setSHAKE_SLOP_TIME_MS(int sHAKE_SLOP_TIME_MS) {
        SHAKE_SLOP_TIME_MS = sHAKE_SLOP_TIME_MS;
    }   

}

你可能想试试开源tinybus。有了它,震动检测就像这样简单。

public class MainActivity extends Activity {

    private Bus mBus;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...

        // Create a bus and attach it to activity
        mBus = TinyBus.from(this).wire(new ShakeEventWire());
    }

    @Subscribe
    public void onShakeEvent(ShakeEvent event) {
        Toast.makeText(this, "Device has been shaken", 
                Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onStart() {
        super.onStart();
        mBus.register(this);
    }

    @Override
    protected void onStop() {
        mBus.unregister(this);
        super.onStop();
    }
}

它采用地震仪进行振动检测。

// Need to implement SensorListener
public class ShakeActivity extends Activity implements SensorListener {
// For shake motion detection.
private SensorManager sensorMgr;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private static final int SHAKE_THRESHOLD = 800;

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start motion detection
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
boolean accelSupported = sensorMgr.registerListener(this,
    SensorManager.SENSOR_ACCELEROMETER,
    SensorManager.SENSOR_DELAY_GAME);

if (!accelSupported) {
    // on accelerometer on this device
    sensorMgr.unregisterListener(this,
            SensorManager.SENSOR_ACCELEROMETER);
}
}

protected void onPause() {
if (sensorMgr != null) {
    sensorMgr.unregisterListener(this,
            SensorManager.SENSOR_ACCELEROMETER);
    sensorMgr = null;
    }
super.onPause();
}

public void onAccuracyChanged(int arg0, int arg1) {
// TODO Auto-generated method stub
}

public void onSensorChanged(int sensor, float[] values) {
if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
    long curTime = System.currentTimeMillis();
    // only allow one update every 100ms.
    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) {
        // yes, this is a shake action! Do something about it!
    }
    last_x = x;
    last_y = y;
    last_z = z;
    }
}
}
}

下面是我的颤抖手势检测代码:

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


/**
 * Listener that detects shake gesture.
 */
public class ShakeEventListener implements SensorEventListener {


  /** Minimum movement force to consider. */
  private static final int MIN_FORCE = 10;

  /**
   * Minimum times in a shake gesture that the direction of movement needs to
   * change.
   */
  private static final int MIN_DIRECTION_CHANGE = 3;

  /** Maximum pause between movements. */
  private static final int MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE = 200;

  /** Maximum allowed time for shake gesture. */
  private static final int MAX_TOTAL_DURATION_OF_SHAKE = 400;

  /** Time when the gesture started. */
  private long mFirstDirectionChangeTime = 0;

  /** Time when the last movement started. */
  private long mLastDirectionChangeTime;

  /** How many movements are considered so far. */
  private int mDirectionChangeCount = 0;

  /** The last x position. */
  private float lastX = 0;

  /** The last y position. */
  private float lastY = 0;

  /** The last z position. */
  private float lastZ = 0;

  /** OnShakeListener that is called when shake is detected. */
  private OnShakeListener mShakeListener;

  /**
   * Interface for shake gesture.
   */
  public interface OnShakeListener {

    /**
     * Called when shake gesture is detected.
     */
    void onShake();
  }

  public void setOnShakeListener(OnShakeListener listener) {
    mShakeListener = listener;
  }

  @Override
  public void onSensorChanged(SensorEvent se) {
    // get sensor data
    float x = se.values[SensorManager.DATA_X];
    float y = se.values[SensorManager.DATA_Y];
    float z = se.values[SensorManager.DATA_Z];

    // calculate movement
    float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);

    if (totalMovement > MIN_FORCE) {

      // get time
      long now = System.currentTimeMillis();

      // store first movement time
      if (mFirstDirectionChangeTime == 0) {
        mFirstDirectionChangeTime = now;
        mLastDirectionChangeTime = now;
      }

      // check if the last movement was not long ago
      long lastChangeWasAgo = now - mLastDirectionChangeTime;
      if (lastChangeWasAgo < MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE) {

        // store movement data
        mLastDirectionChangeTime = now;
        mDirectionChangeCount++;

        // store last sensor data 
        lastX = x;
        lastY = y;
        lastZ = z;

        // check how many movements are so far
        if (mDirectionChangeCount >= MIN_DIRECTION_CHANGE) {

          // check total duration
          long totalDuration = now - mFirstDirectionChangeTime;
          if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE) {
            mShakeListener.onShake();
            resetShakeParameters();
          }
        }

      } else {
        resetShakeParameters();
      }
    }
  }

  /**
   * Resets the shake parameters to their default values.
   */
  private void resetShakeParameters() {
    mFirstDirectionChangeTime = 0;
    mDirectionChangeCount = 0;
    mLastDirectionChangeTime = 0;
    lastX = 0;
    lastY = 0;
    lastZ = 0;
  }

  @Override
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
  }

}

把这个添加到你的活动中:

  private SensorManager mSensorManager;

  private ShakeEventListener mSensorListener;

...

在onCreate()中添加:

    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mSensorListener = new ShakeEventListener();   

    mSensorListener.setOnShakeListener(new ShakeEventListener.OnShakeListener() {

      public void onShake() {
        Toast.makeText(KPBActivityImpl.this, "Shake!", Toast.LENGTH_SHORT).show();
      }
    });

and:

@Override
  protected void onResume() {
    super.onResume();
    mSensorManager.registerListener(mSensorListener,
        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
        SensorManager.SENSOR_DELAY_UI);
  }

  @Override
  protected void onPause() {
    mSensorManager.unregisterListener(mSensorListener);
    super.onPause();
  }