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

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

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


当前回答

下面是另一个代码:

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

其他回答

这里还有另一个实现,它是基于这里的一些技巧以及来自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();
    }
}

下面是一个示例代码。 把这些放到你的活动课上:

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

根据评论-测试这一点:

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

注:

The accelometer should be deactivated onPause and activated onResume to save resources (CPU, Battery). The code assumes we are on planet Earth ;-) and initializes the acceleration to earth gravity. Otherwise you would get a strong "shake" when the application starts and "hits" the ground from free-fall. However, the code gets used to the gravitation due to the low-cut filter and would work also on other planets or in free space, once it is initialized. (you never know how long your application will be in use...;-)

我已经尝试了几种实现,但我想分享一下我自己的实现。 它以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();

            }
        }

    }

}

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


}

玩得开心。

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

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