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

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

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


当前回答

我修改了@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
}

其他回答

我正在为我的大学项目开发一个运动检测和震动检测应用程序。

除了应用程序的原始目标之外,我还从应用程序中分离了库部分(负责运动和震动检测)。该代码是免费的,可在SourceForge上获得,项目名称为“BenderCatch”。我正在制作的文件将在9月中旬左右准备好。 http://sf.net/projects/bendercatch

它使用了一种更精确的方法来检测震动:当你执行震动时,既观察SensorEvents之间的力差,也观察X轴和Y轴上的振动。它甚至可以在每次震动时发出声音(或振动)。

欢迎通过电子邮件raffaele [at] terzigno [dot] com向我询问更多信息

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

            }
        }

    }

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

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

  /* 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...;-)

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

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