我需要添加一个摇功能,将刷新我的Android应用程序。
我所找到的所有文档都涉及实现SensorListener,但Eclipse告诉我它已被弃用,并建议使用SensorEventListener。
有人知道如何创建这个震动控制器吗?
我需要添加一个摇功能,将刷新我的Android应用程序。
我所找到的所有文档都涉及实现SensorListener,但Eclipse告诉我它已被弃用,并建议使用SensorEventListener。
有人知道如何创建这个震动控制器吗?
当前回答
我写了一个检测垂直和水平震动并显示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();
}
}
}
}
其他回答
你可能想试试开源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();
}
}
它采用地震仪进行振动检测。
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);
}
}
我真的很喜欢彼得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);
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();
}
}
玩得开心。
我已经尝试了几种实现,但我想分享一下我自己的实现。 它以g力为单位进行阈值计算。这让我们更容易理解发生了什么,同时也设置了一个好的阈值。
它只是记录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();
}
}
}
}