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

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

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


当前回答

你可能想试试开源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();
    }
}

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

其他回答

和我一起工作,很好 参考

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
}
// 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

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

    public class Shaker implements SensorEventListener{

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

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

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

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

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

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

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

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

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

                valueStack.add(speed);

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

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

                float sumOfValues = 0;
                float avgOfValues = 0;

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

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

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

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


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

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

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

MainActivity.java

public class MainActivity extends Activity implements OnShakerTreshold{


    private Shaker s;

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

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

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

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


}

玩得开心。

package anywheresoftware.b4a.student;

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

public class ShakeEventListener implements SensorEventListener {

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

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

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

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

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

    @Override
    public void onSensorChanged(SensorEvent event) {

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

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

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

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

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

                mShakeTimestamp = now;
                mShakeCount++;

                mListener.onShake(mShakeCount);
            }
        }
    }

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

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

}