我需要添加一个摇功能,将刷新我的Android应用程序。
我所找到的所有文档都涉及实现SensorListener,但Eclipse告诉我它已被弃用,并建议使用SensorEventListener。
有人知道如何创建这个震动控制器吗?
我需要添加一个摇功能,将刷新我的Android应用程序。
我所找到的所有文档都涉及实现SensorListener,但Eclipse告诉我它已被弃用,并建议使用SensorEventListener。
有人知道如何创建这个震动控制器吗?
当前回答
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();
}
}
}
}
和我一起工作,很好 参考
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) {}
}
下面是另一个代码:
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);
}
}
}
下面是我的颤抖手势检测代码:
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();
}
我修改了@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
}