How to refresh app upon shaking the device?
我需要添加一个可以刷新我的Android应用程序的摇动功能。
我找到的所有文档都涉及实现
谁有一个很好的指导我如何创建这个
这是一个示例代码。
把它放到你的活动类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /* 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方法:
1 2 3 4 5 6 | /* 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。
根据评论 - 测试这个:
1 2 3 4 | if (mAccel > 12) { Toast toast = Toast.makeText(getApplicationContext(),"Device has shaken.", Toast.LENGTH_LONG); toast.show(); } |
笔记:
应该在onPause上停用accelometer并在onResume上激活以节省资源(CPU,电池)。
代码假定我们在地球上;-)并初始化加速到地球引力。否则,当应用程序启动时,您将获得强烈的"震动",并从自由落体中"击中"地面。然而,由于低截止滤波器,代码习惯于引力,并且一旦初始化,它也可以在其他行星或自由空间中工作。
(你永远不知道你的应用程序将被使用多久...... ;-)
这是我的摇动手势检测代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 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) { } } |
在您的活动中添加:
1 2 3 | private SensorManager mSensorManager; private ShakeEventListener mSensorListener; |
...
在onCreate()中添加:
1 2 3 4 5 6 7 8 9 | 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(); } }); |
和:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @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(); } |
这是另一个实现,它基于这里的一些技巧以及Android开发人员站点的代码。
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | 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(); } } |
我真的很喜欢Peterdk的回答。我接受了自己对他的代码做了一些调整。
file:ShakeDetector.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 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的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 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); |
我正在为我的大学项目开发??一个运动检测和抖动检测应用程序。
除了应用程序的原始目标,我正在从应用程序中拆分库部分(负责运动和抖动检测)。该代码是免费的,可在SourceForge上获得,项目名称为"BenderCatch"。我正在制作的文档将在9月中旬左右准备好。
http://sf.net/projects/bendercatch
它使用更精确的方法来检测抖动:观察当执行抖动时SensorEvents与X和Y轴上存在的振荡之间的力差。它甚至可以在震动的每次振荡时发出声音(或振动)。
请随时通过电子邮件在raffaele [at] terzigno [dot] com询问我
我写了一个小例子来检测垂直和水平抖动并显示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | 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(); } } } } |
你可以使用地震。这里可以找到一个例子。
我尝试了几种实现,但想分享我自己的实现。
它使用
它只是记录G力的增加,并在超过阈值时触发侦听器。它没有使用任何方向阈值,因为如果你只想注册一个好的震动,你真的不需要它。
当然,您需要在
此外,要检查您需要的阈值,我建议使用以下应用程序(我没有以任何方式连接到该应用程序)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 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(); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 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); } } |
这是另一个代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 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); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 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; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | // 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; } } } } |
您应该订阅
一旦你拥有它,你应该监视某个轴上加速度方向(符号)的突然变化。这将是设备
Shaker.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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(); } } |
玩得开心。
与我合作v.good
参考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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) {} } |
您可能想尝试开源tinybus。有了它,震动检测就像这样容易。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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(); } } |
它使用地震进行震动检测。