如何在摇动设备时刷新应用程序?

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

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

有人知道如何创建shake controller吗?

124409 次浏览
你应该订阅一个SensorEventListener,并获得accelerometer数据。 一旦你有了它,你应该监测在某个轴上加速度方向(符号)的突然变化。这将是一个很好的指示设备的'shake'移动
下面是一个示例代码。 把这个放进你的activity类:

  /* 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,如果设备被震动,则为>

根据评论-测试这一点:

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

注:

加速度计应该去激活onPause和激活onResume以节省资源(CPU,电池)。 该代码假设我们在地球上;-),并初始化地球重力加速度。否则,当应用程序启动时,您将受到强烈的“震动”,并从自由落体“撞击”到地面。然而,由于低切滤波器,代码习惯了引力,一旦初始化,也可以在其他星球或自由空间工作。 (你永远不知道你的应用程序会被使用多久…;-)

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

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();
}
});

和:

@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();
}

下面是另一个代码:

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;


import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;


public class AccelerometerListener implements SensorEventListener {


private SensorManager sensorManager;
private List<Sensor> sensors;
private Sensor sensor;
private long lastUpdate = -1;
private long currentTime = -1;
private Main parent;
private Timer timer;
private int shakes;
private static final Handler mHandler = new Handler();


private float last_x, last_y, last_z;
private float current_x, current_y, current_z, currenForce;
private static final int FORCE_THRESHOLD = 500;
private final int DATA_X = SensorManager.DATA_X;
private final int DATA_Y = SensorManager.DATA_Y;
private final int DATA_Z = SensorManager.DATA_Z;


public AccelerometerListener(Main parent) {
SensorManager sensorService = (SensorManager) parent
.getSystemService(Context.SENSOR_SERVICE);


this.sensorManager = sensorService;
if (sensorService == null)
return;


this.sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (sensors.size() > 0) {
sensor = sensors.get(0);
}


this.parent = parent;
}


public void start() {
if (sensor == null)
return;


sensorManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_GAME);
}


public void stop() {
if (sensorManager == null)
return;


sensorManager.unregisterListener(this);
}


public void onAccuracyChanged(Sensor s, int valu) {


}


public void onSensorChanged(SensorEvent event) {


if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;


currentTime = System.currentTimeMillis();


if ((currentTime - lastUpdate) > 50) {
long diffTime = (currentTime - lastUpdate);
lastUpdate = currentTime;


current_x = event.values[DATA_X];
current_y = event.values[DATA_Y];
current_z = event.values[DATA_Z];


currenForce = Math.abs(current_x + current_y + current_z - last_x
- last_y - last_z)
/ diffTime * 10000;


if (currenForce > FORCE_THRESHOLD) {
shakeDetected();
}
last_x = current_x;
last_y = current_y;
last_z = current_z;


}
}


private void shakeDetected() {
shakes++;


if (shakes == 1) {
if (timer != null) {
timer.cancel();
}


timer = new Timer();
timer.schedule(new TimerTask() {


@Override
public void run() {
if (shakes > 3) {
mHandler.post(new Runnable() {


public void run() {
// shake
}
});
}


shakes = 0;
}
}, 500);
}
}
}

我正在为我的大学项目开发一个运动检测和震动检测应用程序。

除了应用程序的原始目标之外,我还将库部分(负责运动和震动检测)从应用程序中分离出来。该代码是免费的,可在SourceForge上使用项目名称“BenderCatch”。我正在制作的文件将在9月中旬左右准备好。 http://sf.net/projects/bendercatch < / p >

它使用了一种更精确的方法来检测震动:当你执行震动时,既观察SensorEvents之间的力差,也观察X轴和Y轴上的振动。它甚至可以在每次震动时发出声音(或振动)。

欢迎通过电子邮件raffaele [at] terzigno [dot] com向我询问更多信息

我写了一个小例子来检测垂直和水平的震动,并显示Toast

public class Accelerometerka2Activity extends Activity implements SensorEventListener {
private float mLastX, mLastY, mLastZ;
private boolean mInitialized;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private final float NOISE = (float) 8.0;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mInitialized = false;
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
}


protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}


protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}




public void onAccuracyChanged(Sensor sensor, int accuracy) {
// can be safely ignored for this demo
}




public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
if (!mInitialized) {
mLastX = x;
mLastY = y;
mLastZ = z;
mInitialized = true;
} else {
float deltaX = Math.abs(mLastX - x);
float deltaY = Math.abs(mLastY - y);
float deltaZ = Math.abs(mLastZ - z);
if (deltaX < NOISE) deltaX = (float)0.0;
if (deltaY < NOISE) deltaY = (float)0.0;
if (deltaZ < NOISE) deltaZ = (float)0.0;
mLastX = x;
mLastY = y;
mLastZ = z;
if (deltaX > deltaY) {
Toast.makeText(getBaseContext(), "Horizental", Toast.LENGTH_SHORT).show();
} else if (deltaY > deltaX) {
Toast.makeText(getBaseContext(), "Vertical", Toast.LENGTH_SHORT).show();
}
}
}
}

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();
}




}

玩得开心。

这里还有另一个实现,它是基于这里的一些技巧以及来自Android开发人员网站的代码。

MainActivity.java

public class MainActivity extends Activity {


private ShakeDetector mShakeDetector;
private SensorManager mSensorManager;
private Sensor mAccelerometer;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


// ShakeDetector initialization
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mShakeDetector = new ShakeDetector(new OnShakeListener() {
@Override
public void onShake() {
// Do stuff!
}
});
}


@Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
}


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

ShakeDetector.java

package com.example.test;


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


public class ShakeDetector implements SensorEventListener {


// Minimum acceleration needed to count as a shake movement
private static final int MIN_SHAKE_ACCELERATION = 5;


// Minimum number of movements to register a shake
private static final int MIN_MOVEMENTS = 2;


// Maximum time (in milliseconds) for the whole shake to occur
private static final int MAX_SHAKE_DURATION = 500;


// Arrays to store gravity and linear acceleration values
private float[] mGravity = { 0.0f, 0.0f, 0.0f };
private float[] mLinearAcceleration = { 0.0f, 0.0f, 0.0f };


// Indexes for x, y, and z values
private static final int X = 0;
private static final int Y = 1;
private static final int Z = 2;


// OnShakeListener that will be notified when the shake is detected
private OnShakeListener mShakeListener;


// Start time for the shake detection
long startTime = 0;


// Counter for shake movements
int moveCount = 0;


// Constructor that sets the shake listener
public ShakeDetector(OnShakeListener shakeListener) {
mShakeListener = shakeListener;
}


@Override
public void onSensorChanged(SensorEvent event) {
// This method will be called when the accelerometer detects a change.


// Call a helper method that wraps code from the Android developer site
setCurrentAcceleration(event);


// Get the max linear acceleration in any direction
float maxLinearAcceleration = getMaxCurrentLinearAcceleration();


// Check if the acceleration is greater than our minimum threshold
if (maxLinearAcceleration > MIN_SHAKE_ACCELERATION) {
long now = System.currentTimeMillis();


// Set the startTime if it was reset to zero
if (startTime == 0) {
startTime = now;
}


long elapsedTime = now - startTime;


// Check if we're still in the shake window we defined
if (elapsedTime > MAX_SHAKE_DURATION) {
// Too much time has passed. Start over!
resetShakeDetection();
}
else {
// Keep track of all the movements
moveCount++;


// Check if enough movements have been made to qualify as a shake
if (moveCount > MIN_MOVEMENTS) {
// It's a shake! Notify the listener.
mShakeListener.onShake();


// Reset for the next one!
resetShakeDetection();
}
}
}
}


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


private void setCurrentAcceleration(SensorEvent event) {
/*
*  BEGIN SECTION from Android developer site. This code accounts for
*  gravity using a high-pass filter
*/


// alpha is calculated as t / (t + dT)
// with t, the low-pass filter's time-constant
// and dT, the event delivery rate


final float alpha = 0.8f;


// Gravity components of x, y, and z acceleration
mGravity[X] = alpha * mGravity[X] + (1 - alpha) * event.values[X];
mGravity[Y] = alpha * mGravity[Y] + (1 - alpha) * event.values[Y];
mGravity[Z] = alpha * mGravity[Z] + (1 - alpha) * event.values[Z];


// Linear acceleration along the x, y, and z axes (gravity effects removed)
mLinearAcceleration[X] = event.values[X] - mGravity[X];
mLinearAcceleration[Y] = event.values[Y] - mGravity[Y];
mLinearAcceleration[Z] = event.values[Z] - mGravity[Z];


/*
*  END SECTION from Android developer site
*/
}


private float getMaxCurrentLinearAcceleration() {
// Start by setting the value to the x value
float maxLinearAcceleration = mLinearAcceleration[X];


// Check if the y value is greater
if (mLinearAcceleration[Y] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Y];
}


// Check if the z value is greater
if (mLinearAcceleration[Z] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Z];
}


// Return the greatest value
return maxLinearAcceleration;
}


private void resetShakeDetection() {
startTime = 0;
moveCount = 0;
}


// (I'd normally put this definition in it's own .java file)
public interface OnShakeListener {
public void onShake();
}
}

你可以使用地震。一个例子可以在在这里中找到。

// 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;
}
}
}
}
我已经尝试了几种实现,但想分享我自己的。 它使用G-force作为门限计算的单元。这让我们更容易理解发生了什么,同时也可以设置一个好的阈值

它只是记录G力的增加,如果超过阈值就触发侦听器。它不使用任何方向阈值,因为如果你只是想记录一个好的震动,你真的不需要这个。

当然你需要在Activity中对这个监听器进行标准注册和un -注册。

此外,为了检查你需要的阈值,我推荐下面的程序(我没有以任何方式连接到那个应用程序)

    public class UmitoShakeEventListener implements SensorEventListener {


/**
* The gforce that is necessary to register as shake. (Must include 1G
* gravity)
*/
private final float shakeThresholdInGForce = 2.25F;


private final float gravityEarth = SensorManager.GRAVITY_EARTH;


private OnShakeListener listener;


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


public interface OnShakeListener {
public void onShake();
}


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


}


@Override
public void onSensorChanged(SensorEvent event) {


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


float gX = x / gravityEarth;
float gY = y / gravityEarth;
float gZ = z / gravityEarth;


//G-Force will be 1 when there is no movement. (gravity)
float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);






if (gForce > shakeThresholdInGForce) {
listener.onShake();


}
}


}


}

我真的很喜欢彼得dk的回答。我自作主张对他的代码做了一些调整。

文件:ShakeDetector.java

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


public class ShakeDetector implements SensorEventListener {


// The gForce that is necessary to register as shake. Must be greater than 1G (one earth gravity unit)
private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
private static final int SHAKE_SLOP_TIME_MS = 500;
private static final int SHAKE_COUNT_RESET_TIME_MS = 3000;


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 + SHAKE_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);
}
}
}
}

另外,不要忘记需要向SensorManager注册一个ShakeDetector实例。

// ShakeDetector initialization
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mShakeDetector = new ShakeDetector();
mShakeDetector.setOnShakeListener(new OnShakeListener() {


@Override
public void onShake(int count) {
handleShakeEvent(count);
}
});


mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
 package com.example.shakingapp;


import android.app.Activity;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;




public class MainActivity extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private boolean color = false;
private View view;
private long lastUpdate;




/** Called when the activity is first created. */


@Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);


super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = findViewById(R.id.textView);
view.setBackgroundColor(Color.GREEN);


sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
lastUpdate = System.currentTimeMillis();
}


@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
getAccelerometer(event);
}


}


private void getAccelerometer(SensorEvent event) {
float[] values = event.values;
// Movement
float x = values[0];
float y = values[1];
float z = values[2];


System.out.println(x);
System.out.println(y);
System.out.println(z);
System.out.println(SensorManager.GRAVITY_EARTH );


float accelationSquareRoot = (x * x + y * y + z * z)
/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);


long actualTime = System.currentTimeMillis();
if (accelationSquareRoot >= 2) //
{
if (actualTime - lastUpdate < 200) {
return;
}
lastUpdate = actualTime;
Toast.makeText(this, "Device was shuffed "+accelationSquareRoot, Toast.LENGTH_SHORT)
.show();
if (color) {
view.setBackgroundColor(Color.GREEN);


} else {
view.setBackgroundColor(Color.RED);
}
color = !color;
}
}


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


}


@Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}


@Override
protected void onPause() {
// unregister listener
super.onPause();
sensorManager.unregisterListener(this);
}
}
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();
}
}

它使用地震进行抖动检测。

和我一起工作很好 参考 < / p >

public class ShakeEventListener implements SensorEventListener {
public final static int SHAKE_LIMIT = 15;
public final static int LITTLE_SHAKE_LIMIT = 5;


private SensorManager mSensorManager;
private float mAccel = 0.00f;
private float mAccelCurrent = SensorManager.GRAVITY_EARTH;
private float mAccelLast = SensorManager.GRAVITY_EARTH;


private ShakeListener listener;


public interface ShakeListener {
public void onShake();
public void onLittleShake();
}


public ShakeEventListener(ShakeListener l) {
Activity a = (Activity) l;
mSensorManager = (SensorManager) a.getSystemService(Context.SENSOR_SERVICE);
listener = l;
registerListener();
}


public ShakeEventListener(Activity a, ShakeListener l) {
mSensorManager = (SensorManager) a.getSystemService(Context.SENSOR_SERVICE);
listener = l;
registerListener();
}


public void registerListener() {
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}


public void unregisterListener() {
mSensorManager.unregisterListener(this);
}


public void onSensorChanged(SensorEvent se) {
float x = se.values[0];
float y = se.values[1];
float z = se.values[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) FloatMath.sqrt(x*x + y*y + z*z);
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta;
if(mAccel > SHAKE_LIMIT)
listener.onShake();
else if(mAccel > LITTLE_SHAKE_LIMIT)
listener.onLittleShake();
}


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

我修改了@peceps的答案,并使它的kotlin版本。我还添加了LifecycleOwner参数,使其能够感知生命周期。

import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import kotlin.math.abs




/**
* Listener that detects shake gesture.
*/
class ShakeEventListener(
lifecycleOwner: LifecycleOwner,
private val sensorManager: SensorManager,
private val onShake: () -> Unit = {}
) : SensorEventListener, DefaultLifecycleObserver {
/** Time when the gesture started.  */
private var mFirstDirectionChangeTime: Long = 0


/** Time when the last movement started.  */
private var mLastDirectionChangeTime: Long = 0


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


/** The last x position.  */
private var lastX = 0f


/** The last y position.  */
private var lastY = 0f


/** The last z position.  */
private var lastZ = 0f


init {
sensorManager.registerListener(
this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI
)
// observe lifecycle state
lifecycleOwner.lifecycle.addObserver(this)
}




override fun onResume(owner: LifecycleOwner) {
sensorManager.registerListener(
this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI
)
}




override fun onPause(owner: LifecycleOwner) {
sensorManager.unregisterListener(this)
}


override fun onSensorChanged(se: SensorEvent) {
// get sensor data
val x = se.values[0]
val y = se.values[1]
val z = se.values[2]


// calculate movement
val totalMovement = abs(x + y + z - lastX - lastY - lastZ)
if (totalMovement > MIN_FORCE) {


// get time
val now = System.currentTimeMillis()


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


// check if the last movement was not long ago
val lastChangeWasAgo = now - mLastDirectionChangeTime
if (lastChangeWasAgo < MAX_PAUSE_BETWEEN_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
val totalDuration = now - mFirstDirectionChangeTime
if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE) {
onShake()
resetShakeParameters()
}
}
} else {
resetShakeParameters()
}
}
}


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


override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}


companion object {
/** Minimum movement force to consider.  */
private const val MIN_FORCE = 10


/**
* Minimum times in a shake gesture that the direction of movement needs to
* change.
*/
private const val MIN_DIRECTION_CHANGE = 3


/** Maximum pause between movements.  */
private const val MAX_PAUSE_BETWEEN_DIRECTION_CHANGE = 200


/** Maximum allowed time for shake gesture.  */
private const val MAX_TOTAL_DURATION_OF_SHAKE = 400
}
}

在您的活动中,添加以下代码,使其检测震动事件:

ShakeEventListener(this, sensorManager){
// onShake logic
}