【问题标题】:Shake detection via service通过服务进行抖动检测
【发布时间】:2015-04-11 03:20:17
【问题描述】:

我在创建抖动检测服务时遇到问题

background_service

package com.likith.shakedetector;

import android.app.Service;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.IBinder;
import android.widget.Toast;

public class Background_service extends Service implements SensorEventListener
{
SensorManager sensorManager;
int count=0;

private float lastX = 0;
private float lastY = 0;
private float lastZ = 0;
private static final int MIN_FORCE = 10;
private static final int MIN_DIRECTION_CHANGE = 3;
private static final int MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE = 200;
private static final int MAX_TOTAL_DURATION_OF_SHAKE = 400;
private long mFirstDirectionChangeTime = 0;
private long mLastDirectionChangeTime;
private int mDirectionChangeCount = 0;

@Override   
public IBinder onBind(Intent intent) {
    return null;
}

public void onCreate()
{
    super.onCreate();
}

public void onDestroy() 
{
    super.onDestroy();
    sensorManager.unregisterListener(this);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) 
{
    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    sensorManager.registerListener(this,sensorManager
            .getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_UI);

    return START_STICKY;
}

public void onStart(Intent intent, int startId)
{
    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    sensorManager.registerListener(this,sensorManager
            .getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_UI);
}

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

}

@SuppressWarnings("deprecation")
private void getAccelerometer(SensorEvent event) 
{
    //Toast.makeText(getApplicationContext(),"Shaked",Toast.LENGTH_LONG).show();

    float x = event.values[SensorManager.DATA_X];
    float y = event.values[SensorManager.DATA_Y];
    float z = event.values[SensorManager.DATA_Z];

    float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);

    if (totalMovement <= MIN_FORCE) 
    {
        long now = System.currentTimeMillis();
        if (mFirstDirectionChangeTime == 0) 
        {
            mFirstDirectionChangeTime = now;
            mLastDirectionChangeTime = now;
        }

        long lastChangeWasAgo = now - mLastDirectionChangeTime;

        if (lastChangeWasAgo < MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE) 
        {
            mLastDirectionChangeTime = now;
            mDirectionChangeCount++;

            lastX = x;
            lastY = y;
            lastZ = z;

            if (mDirectionChangeCount >= MIN_DIRECTION_CHANGE) 
            {
                long totalDuration = now - mFirstDirectionChangeTime;
                if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE) 
                {
                    Toast.makeText(getApplicationContext(),"Shaked",Toast.LENGTH_LONG).show();
                    resetShakeParameters();
                }
            }

        }
        else 
        {
            resetShakeParameters();
        }
    }
}


public void onSensorChanged(SensorEvent event) 
{
    getAccelerometer(event);
}

protected void onResume() 
{
    sensorManager.registerListener(this,sensorManager
            .getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_UI);
}

protected void onPause()
{
    sensorManager.unregisterListener(this);
}

private void resetShakeParameters() 
{
    mFirstDirectionChangeTime = 0;
    mDirectionChangeCount = 0;
    mLastDirectionChangeTime = 0;
    lastX = 0;
    lastY = 0;
    lastZ = 0;
}

当我运行此服务时,它会连续打印 toast 消息。

如何更改代码,以便当我摇动设备时,它只打印一次 toast 消息?

【问题讨论】:

    标签: java android eclipse adt


    【解决方案1】:

    你有

    float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);
    

    您可能应该单独执行每个轴 - 因为每个轴的变化独立于其他轴。

    float xMovement = Math.abs(x - lastX);
    float yMovement = Math.abs(y - lastY);
    float zMovement = Math.abs(z - lastZ);
    
    if ((xMovement > MIN_FORCE) ||
        (yMovement > MIN_FORCE) ||
        (zMovement > MIN_FORCE)) {
         // motion detected
    }
    

    我正在做类似的事情,发现最好先检查延迟 (MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE)。

    对于 Android API 18,有一个重要的运动传感器,如果 Android 设备中存在可能对您的目的有效。

    http://developer.android.com/reference/android/hardware/Sensor.html#TYPE_SIGNIFICANT_MOTION

    【讨论】:

      【解决方案2】:

      试试这个代码

      Background_service.java

      package com.likith.shakedetector;
      
      import com.likith.gesturelauncherPro.gestureDrawer;
      
      import android.app.Service;
      import android.content.Intent;
      import android.hardware.Sensor;
      import android.hardware.SensorEvent;
      import android.hardware.SensorManager;
      import android.os.IBinder;
      
      public class Background_service extends Service implements com.likith.shakedetector.shake.Listener
      {
      
          @Override
          public void onCreate() 
          {
              SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
              shake sd = new shake(this);
              sd.start(sensorManager);
          }
      
          @Override
          public void hearShake() 
          {
              //Toast.makeText(getApplicationContext(),"Shaked",Toast.LENGTH_LONG).show();
      
              Intent notificationIntent = new Intent(this, gestureDrawer.class);
              notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
              startActivity(notificationIntent);
          }
      
          public void onSensorChanged(SensorEvent event) {
              // TODO Auto-generated method stub
      
          }
      
          public void onAccuracyChanged(Sensor sensor, int accuracy) {
              // TODO Auto-generated method stub
      
          }
      
          @Override
          public IBinder onBind(Intent intent) {
              // TODO Auto-generated method stub
              return null;
          }
      }
      

      shake.java

      package com.likith.shakedetector;
      
      import android.hardware.Sensor;
      import android.hardware.SensorEvent;
      import android.hardware.SensorEventListener;
      import android.hardware.SensorManager;
      import java.util.ArrayList;
      import java.util.List;
      
      /**
      * Detects phone shaking. If > 75% of the samples taken in the past 0.5s are
      * accelerating, the device is a) shaking, or b) free falling 1.84m (h =
      * 1/2*g*t^2*3/4).
      *
      * @author Bob Lee (bob@squareup.com)
      * @author Eric Burke (eric@squareup.com)
      */
      public class shake implements SensorEventListener 
      {
      
          private static final int ACCELERATION_THRESHOLD = 13;
      
          public interface Listener 
          {
              void hearShake();
          }
      
          private final SampleQueue queue = new SampleQueue();
          private final Listener listener;
      
          private SensorManager sensorManager;
          private Sensor accelerometer;
      
          public shake(Listener listener) 
          {
              this.listener = listener;
          }
      
          public boolean start(SensorManager sensorManager) 
          {
              if (accelerometer != null) 
              {
                  return true;
              }
      
              accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
      
              // If this phone has an accelerometer, listen to it.
              if (accelerometer != null) 
              {
                  this.sensorManager = sensorManager;
                  sensorManager.registerListener(this, accelerometer,SensorManager.SENSOR_DELAY_FASTEST);
              }
              return accelerometer != null;
          }
      
          /**
          * Stops listening.  Safe to call when already stopped.  Ignored on devices
          * without appropriate hardware.
          */
          public void stop() 
          {
              if (accelerometer != null) 
              {
                  sensorManager.unregisterListener(this, accelerometer);
                  sensorManager = null;
                  accelerometer = null;
              }
          }
      
          @Override public void onSensorChanged(SensorEvent event)
          {
              boolean accelerating = isAccelerating(event);
              long timestamp = event.timestamp;
              queue.add(timestamp, accelerating);
      
              if (queue.isShaking()) 
              {
                  queue.clear();
                  listener.hearShake();
              }
          }
      
          /** Returns true if the device is currently accelerating. */
          private boolean isAccelerating(SensorEvent event)
          {
              float ax = event.values[0];
              float ay = event.values[1];
              float az = event.values[2];
      
              // Instead of comparing magnitude to ACCELERATION_THRESHOLD,
              // compare their squares. This is equivalent and doesn't need the
              // actual magnitude, which would be computed using (expesive) Math.sqrt().
              final double magnitudeSquared = ax * ax + ay * ay + az * az;
              return magnitudeSquared > ACCELERATION_THRESHOLD * ACCELERATION_THRESHOLD;
          }
      
          /** Queue of samples. Keeps a running average. */
          static class SampleQueue 
          {
              /** Window size in ns. Used to compute the average. */
              private static final long MAX_WINDOW_SIZE = 500000000; // 0.5s
              private static final long MIN_WINDOW_SIZE = MAX_WINDOW_SIZE >> 1; // 0.25s
      
               /**
                * Ensure the queue size never falls below this size, even if the device
                * fails to deliver this many events during the time window. The LG Ally
                * is one such device.
                */
      
              private static final int MIN_QUEUE_SIZE = 4;
      
              private final SamplePool pool = new SamplePool();
      
              private Sample oldest;
              private Sample newest;
              private int sampleCount;
              private int acceleratingCount;
      
               /**
                * Adds a sample.
                *
                * @param timestamp    in nanoseconds of sample
                * @param accelerating true if > {@link #ACCELERATION_THRESHOLD}.
                */
              void add(long timestamp, boolean accelerating) 
              {
                  // Purge samples that proceed window.
                  purge(timestamp - MAX_WINDOW_SIZE);
      
                  // Add the sample to the queue.
                  Sample added = pool.acquire();
                  added.timestamp = timestamp;
                  added.accelerating = accelerating;
                  added.next = null;
                  if (newest != null) 
                  {
                      newest.next = added;
                  }
                  newest = added;
                  if (oldest == null) 
                  {
                      oldest = added;
                  }
      
                  // Update running average.
                  sampleCount++;
                  if (accelerating) 
                  {
                      acceleratingCount++;
                  }
              }
      
       /** Removes all samples from this queue. */
       void clear() {
         while (oldest != null) {
           Sample removed = oldest;
           oldest = removed.next;
           pool.release(removed);
         }
         newest = null;
         sampleCount = 0;
         acceleratingCount = 0;
       }
      
       /** Purges samples with timestamps older than cutoff. */
       void purge(long cutoff) {
         while (sampleCount >= MIN_QUEUE_SIZE
             && oldest != null && cutoff - oldest.timestamp > 0) {
           // Remove sample.
           Sample removed = oldest;
           if (removed.accelerating) {
             acceleratingCount--;
           }
           sampleCount--;
      
           oldest = removed.next;
           if (oldest == null) {
             newest = null;
           }
           pool.release(removed);
         }
       }
      
       /** Copies the samples into a list, with the oldest entry at index 0. */
       List<Sample> asList() {
         List<Sample> list = new ArrayList<Sample>();
         Sample s = oldest;
         while (s != null) {
           list.add(s);
           s = s.next;
         }
         return list;
       }
      
       /**
        * Returns true if we have enough samples and more than 3/4 of those samples
        * are accelerating.
        */
       boolean isShaking() {
         return newest != null
             && oldest != null
             && newest.timestamp - oldest.timestamp >= MIN_WINDOW_SIZE
             && acceleratingCount >= (sampleCount >> 1) + (sampleCount >> 2);
       }
      }
      
      /** An accelerometer sample. */
      static class Sample {
       /** Time sample was taken. */
       long timestamp;
      
       /** If acceleration > {@link #ACCELERATION_THRESHOLD}. */
       boolean accelerating;
      
       /** Next sample in the queue or pool. */
       Sample next;
      }
      
      /** Pools samples. Avoids garbage collection. */
      static class SamplePool {
       private Sample head;
      
       /** Acquires a sample from the pool. */
       Sample acquire() {
         Sample acquired = head;
         if (acquired == null) {
           acquired = new Sample();
         } else {
           // Remove instance from pool.
           head = acquired.next;
         }
         return acquired;
       }
      
       /** Returns a sample to the pool. */
       void release(Sample sample) {
         sample.next = head;
         head = sample;
       }
      }
      
      @Override public void onAccuracyChanged(Sensor sensor, int accuracy) {
      }
      }
      

      清单

      <service android:name="com.likith.shakedetector.Background_service" />
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-01
        • 1970-01-01
        相关资源
        最近更新 更多