วิธีการรีเฟรชแอพเมื่อเขย่าอุปกรณ์


254

ฉันต้องเพิ่มคุณสมบัติการสั่นที่จะรีเฟรชแอปพลิเคชัน Android ของฉัน

ทั้งหมดที่ฉันพบเอกสารที่เกี่ยวข้องกับการดำเนินการแต่คราสบอกฉันก็เลิกและแนะนำSensorListenerSensorEventListener

มีใครบ้างที่มีคำแนะนำที่ดีเกี่ยวกับการสร้างสิ่งนี้shake controller?


พบตัวอย่างที่ใช้งานได้ล่าสุด: android.hlidskialf.com/blog/code/…
Sara

ตั้งแต่วิธีการแก้ปัญหาที่ URL ที่กำหนดโดยซาร่าใช้ระดับเลิกผมแก้ไขเล็กน้อยมันนี่ที่จะทำให้มันทำงาน
Sigwann

17
นี่คือเก่า แต่เพิ่งมาข้ามมันและมีการ +1 สำหรับชื่อ
codeMagic

คำตอบ:


317

นี่คือตัวอย่างรหัส ใส่สิ่งนี้ลงในคลาสกิจกรรมของคุณ:

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

และเพิ่มสิ่งนี้ในวิธีการสร้างของคุณ:

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

หมายเหตุ:

ควรปิดการทำงานของAccelometer บนหยุดชั่วคราวและเปิดใช้งานบนหน้าจอเพื่อประหยัดทรัพยากร (CPU, แบตเตอรี่) รหัสถือว่าเราอยู่บนดาวเคราะห์โลก ;-) และเริ่มต้นการเร่งความเร็วสู่แรงโน้มถ่วงของโลก มิฉะนั้นคุณจะได้ "สั่น" ที่แข็งแกร่งเมื่อแอปพลิเคชั่นเริ่มต้นและ "กระทบ" พื้นจากการตกฟรี อย่างไรก็ตามรหัสจะถูกนำไปใช้กับความโน้มถ่วงเนื่องจากตัวกรองที่ตัดต่ำและจะทำงานบนดาวเคราะห์ดวงอื่นหรือในพื้นที่ว่างเมื่อมันเริ่มต้น (คุณไม่มีทางรู้ว่าจะมีการใช้งานใบสมัครของคุณนานเท่าไร ... ;-)


10
รหัสบรรทัดนี้ mAccel = mAccel * 0.9f + delta; // perform low-cut filterควรจะเป็นmAccel = mAccel * 0.9f + delta * 0.1f; // perform low-cut filterหรือไม่?
Randy Sugianto 'Yuku'

3
ทำได้ดีนี่! ฉันได้เพิ่มการตรวจสอบเพื่อหลีกเลี่ยงการสั่นบ่อยเกินไป (ในแอปของฉันฉันตั้งไว้ที่ 750 มิลลิวินาทีหลังจากการสั่นครั้งสุดท้าย) ... Calendar last = Calendar.getInstance(); Calendar now = Calendar.getInstance(); last.setTime(last_date); now.setTime(new Date()); long diff = now.getTimeInMillis() - last.getTimeInMillis(); if(diff >= 750) { ... } ชื่อวิธีการควรถูกต้อง (ฉันไม่มีรหัสกับฉัน ... )
TesX

9
คอมไพเลอร์แนะนำให้ใช้: android.util.FloatMath.sqrt(x*x + y*y + z*z);แทนที่จะหลีกเลี่ยงการแปลง
Casebash

3
ในการทดสอบให้ใช้สิ่งต่อไปนี้: if (mAccel> 12) {Toast toast = Toast.makeText (getApplicationContext (), "Device shaken.", Toast.LENGTH_LONG); toast.show (); }

1
ฉันจะตรวจสอบค่าของ mAccel ได้ที่ไหน ใน onCreate ของฉันหรือภายในของ OnSernsorChanged?
Vanquiza

128

นี่คือรหัสของฉันสำหรับการตรวจจับท่าทางสั่น:

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

และ:

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

2
ทำไมคุณลงทะเบียนผู้ฟังสองครั้งหนึ่งครั้งใน onCreate และอีกครั้งใน onResume onCreate จะไม่ถูกเรียกโดยไม่มี onResume ดังนั้นคุณสามารถลบการเรียกใช้การลงทะเบียนใน onCreate
Matthias

1
นอกจากนี้หากลงทะเบียนใน onResume คุณอาจต้องการยกเลิกการลงทะเบียนใน onPause ไม่ใช่ onStop นอกจากนั้นสิ่งที่ดีชื่นชมมาก
Matthias

1
ผู้ฟังควรยกเลิกการลงทะเบียนใน onPause () ไม่ใช่ onStop () หากคุณออกจากโทรศัพท์ของคุณในกิจกรรมนี้มันจะ "กิน" แบตเตอรี่ทั้งหมดของคุณ
lomza

2
@ lomza คุณน่าจะถูกต้องก็ควรยกเลิกการลงทะเบียน onPause () ตอนนี้เปลี่ยนไป
peceps

1
อย่าลืมmSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);onCreate () มิฉะนั้นทำงานได้อย่างยอดเยี่ยม! ขอบคุณ!
BVB

33

นี่คืออีกหนึ่งการใช้งานที่สร้างขึ้นจากเคล็ดลับบางประการในที่นี่รวมถึงโค้ดจากไซต์นักพัฒนาซอฟต์แวร์ 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();
    }
}

Hi! ฉันจะตั้งค่าการโทรหลังจากสั่นไหวคุณมีตัวอย่างอะไรบ้างในการทำงานนี้?
มูฮัมหมัด Usman Ghani

ฉันไม่แน่ใจว่าคุณหมายถึงอะไรโดย "หลังจากเขย่า" วิธีการ onShake () ได้รับการเรียกเมื่อตรวจพบการสั่น คุณต้องการรอจนกว่าการเขย่าจะจบหรือไม่ ถ้าเป็นเช่นนั้นคุณจะต้องเพิ่มการตั้งค่าสถานะหรือบางอย่างภายใน onSensorChanged () และเปลี่ยนวิธีและเมื่อมีการเรียก resetShakeDetection ()
Ben Jakuben

@BenJakuben ฉันจะยืนยันรูปแบบการเขย่านี้ได้อย่างไร ฉันจะเก็บไว้ในฐานข้อมูล SQLite เพื่อการตรวจสอบในอนาคตได้อย่างไร
sam_k

ฉันจะนับการสั่นไหวในDoShake()ฟังก์ชั่นได้อย่างไร?
Si8

9

ฉันชอบคำตอบของ Peterdk จริงๆ ฉันเอามันมาทำเองเพื่อปรับแต่งโค๊ดคู่กับรหัสของเขา

ไฟล์: 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);
            }
        }
    }
}

นอกจากนี้อย่าลืมว่าคุณต้องลงทะเบียนอินสแตนซ์ของ ShakeDetector กับ SensorManager

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

2
นอกจากนี้ที่ดีมาก ฉันกำลังคิดเกี่ยวกับการทำสิ่งที่คล้ายกัน แต่มันก็ดีพอสำหรับลูกค้าของฉันเหมือนเดิม เยี่ยมมาก!
Peterdk

1
ฉันจะเปลี่ยนSHAKE_THRESHOLD_GRAVITYไป 1.7F เพื่อป้องกันไม่ให้ผู้อ่านจากการคิดว่าคำตอบนี้ไม่ได้ทำงานเพราะพวกเขามีที่จะเขย่าค่อนข้างยากเนื่องจากค่าที่ตั้งไว้เป็น2.7F
ChuongPham

@Akos ฉันจะยืนยันรูปแบบการเขย่านี้ได้อย่างไร ฉันจะเก็บไว้ในฐานข้อมูล SQLite เพื่อการตรวจสอบในอนาคตได้อย่างไร
sam_k

1
countตัวแปรใน onShake บอกคุณกี่ครั้งอุปกรณ์ที่ถูกเขย่า
Akos Cz

1
ดีมากฉันจะใช้SystemClock.elapsedRealtime()แทนSystem.currentTimeMillis()และเริ่มต้น mShakeTimestamp ด้วยวิธีเดียวกันแทนที่จะเป็น 0
Massimo

4

ฉันกำลังพัฒนาแอพตรวจจับการเคลื่อนไหวและการตรวจจับการสั่นไหวสำหรับโครงการมหาวิทยาลัยของฉัน

นอกเหนือจากเป้าหมายดั้งเดิมของแอปพลิเคชันฉันกำลังแยกส่วนห้องสมุด (รับผิดชอบการตรวจจับการเคลื่อนไหวและการสั่น) จากแอป รหัสนี้ฟรีมีอยู่ใน SourceForge พร้อมชื่อโครงการ "BenderCatch" เอกสารที่ฉันผลิตจะพร้อมประมาณกลางเดือนกันยายน http://sf.net/projects/bendercatch

มันใช้วิธีที่แม่นยำกว่าในการตรวจจับการสั่น: ดูความแตกต่างของแรงระหว่าง SensorEvents และความผันผวนที่มีอยู่ในแกน X และ Y เมื่อคุณสั่น มันยังสามารถส่งเสียง (หรือสั่น) ในการสั่นแต่ละครั้ง

อย่าลังเลที่จะถามฉันเพิ่มเติมทางอีเมลที่ raffaele [at] terzigno [dot] com


4

ฉันได้เขียนตัวอย่างเล็ก ๆ 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();
            }
        }
    }
}

4

คุณสามารถใช้คลื่นไหวสะเทือน ตัวอย่างที่สามารถพบได้ที่นี่


4

ฉันได้ลองใช้งานหลายครั้ง แต่ต้องการแบ่งปันด้วยตัวเอง มันใช้G-forceเป็นหน่วยสำหรับการคำนวณเกณฑ์ มันทำให้ง่ายขึ้นเล็กน้อยในการเข้าใจสิ่งที่เกิดขึ้นและการตั้งค่าเกณฑ์ที่ดี

มันเป็นเพียงการลงทะเบียนเพิ่มขึ้นในแรง G และทริกเกอร์ผู้ฟังถ้ามันเกินเกณฑ์ มันไม่ได้ใช้ธรณีประตูทิศทางใด ๆ ทำให้คุณไม่จำเป็นต้องใช้มันจริงๆถ้าคุณแค่อยากจะสั่นไหว

ของหลักสูตรที่คุณจำเป็นต้องมีมาตรฐานการลงทะเบียนและ ActivityUN-การลงทะเบียนของผู้ฟังในนี้

นอกจากนี้เพื่อตรวจสอบว่าคุณต้องการขีด จำกัด ใดฉันขอแนะนำแอพต่อไปนี้ (ฉันไม่ได้เชื่อมต่อกับแอพนั้น ๆ )

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

            }
        }

    }

}

มันอาจจะแม่นยำมากขึ้น แต่ด้วยค่าใช้จ่ายในการคำนวณอย่างหนักเช่น sqrt และส่วนย่อยลอยใน OnSensorChanged ... ฉันจะไปกับคนอื่นถ้าแอปพลิเคชั่นหนักมาก!
rupps

ฉันสงสัยว่าคณิตศาสตร์แบบลอยตัวเล็ก ๆ น้อย ๆ ในวันนี้ บางทีเมื่อเราอยู่ในอุปกรณ์ Android 1.6
Peterdk

developer.android.com/training/articles/ ...... และรูทีนของคุณเรียกว่าบางร้อยครั้งต่อวินาที กินแบตเตอรี่ที่ยอดเยี่ยม!
rupps

ฉันชอบการอ่านมากกว่าการเพิ่มขึ้นของการใช้งาน CPU เล็กน้อย 2 x ไม่มีอะไรที่ยังไม่มากนัก แต่ทุกคนมีความชอบของตัวเอง :)
Peterdk

แน่นอนว่าฉันชอบกิจวัตรที่รันเร็วกว่าสองเท่ามันมักจะจ่ายออกไป: P
rupps

3

นี่คือรหัสอื่นสำหรับสิ่งนี้:

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

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

}

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

2

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


}

มีความสุข.


แก้ไขลิงก์ไปที่ "ตัวนับการหมุนหน้าจอรีเซ็ต"
Mertuarez

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

รหัสนี้มีรหัสที่เลิกใช้แล้ว เช่น SensorManager.SENSOR_ACCELEROMETER
fiacobelli

2

คุณควรสมัครสมาชิกSensorEventListenerและรับaccelerometerข้อมูล เมื่อคุณมีแล้วคุณควรตรวจสอบการเปลี่ยนแปลงทิศทาง (เครื่องหมาย) ของการเร่งความเร็วในแกนที่แน่นอน มันจะเป็นตัวบ่งชี้ที่ดีสำหรับการ'shake'เคลื่อนไหวของอุปกรณ์


1

v. การอ้างอิงที่ดี

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

0

คุณอาจต้องการที่จะลองมาเปิด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();
    }
}

มันใช้แผ่นดินไหวสำหรับตรวจจับการสั่นไหว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.