最近要實現一個手機搖晃的功能。

想到這個功能可能應用廣泛,比如搖晃手機換圖片、截圖、洗牌、結束當前程式等,所以找了些資料,並加以改進,將此功能封裝成類(ShakeDetector),方便今後使用。

搖晃檢測基於加速感應器(Sensor.TYPE_ACCELEROMETER)。

由於重力的存在,當手機靜止放于桌面時,加速感應器也是有加速度的。所以,僅通過是否有加速度來判斷搖晃是不行的。

那麼,判斷加速度的變化吧。在一個較短的時間間隔求出加速度的差值,跟一個指定的閾值比較,如果差值大於閾值,則認為是搖晃發生了。ClingMarks的方法將x、y、z方向的加速度差值簡單的加起來,我認為不是很準確。

加速度是向量,求差應該是各方向的差值平方後相加,再開方。(數學忘光了,應該沒記錯吧。

所以就有了這行代碼:

 float delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / diffTime * 10000;

功能封裝成類ShakeDetector,實現了SensorEventListener介面,用於向系統註冊感應器事件的Listener。

package zhengzhiren.android.hardware;

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

/**
* 用於檢測手機晃動
*
* @author 鄭智仁
*/
public class ShakeDetector implements SensorEventListener {
/**
* 檢測的時間間隔
*/
static final int UPDATE_INTERVAL = 100;
/**
* 上一次檢測的時間
*/
long mLastUpdateTime;
/**
* 上一次檢測時,加速度在x、y、z方向上的分量,用於和當前加速度比較求差。
*/
float mLastX, mLastY, mLastZ;
CoNtext mCoNtext;
SensorManager mSensorManager;
ArrayList<OnShakeListener> mListeners;
/**
* 搖晃檢測閾值,決定了對搖晃的敏感程度,越小越敏感。
*/
public int shakeThreshold = 5000;

public ShakeDetector(CoNtext coNtext) {
mCoNtext = coNtext;
mSensorManager = (SensorManager) coNtext
.getSystemService(CoNtext.SENSOR_SERVICE);
mListeners = new ArrayList<OnShakeListener>();
}

/**
* 當搖晃事件發生時,接收通知
*/
public interface OnShakeListener {
/**
* 當手機晃動時被調用
*/
void onShake();
}

/**
* 註冊OnShakeListener,當搖晃時接收通知
*
* @param listener
*/
public void registerOnShakeListener(OnShakeListener listener) {
if (mListeners.contains(listener))
return;
mListeners.add(listener);
}

/**
* 移除已經註冊的OnShakeListener
*
* @param listener
*/
public void unregisterOnShakeListener(OnShakeListener listener) {
mListeners.remove(listener);
}

/**
* 啟動搖晃檢測
*/
public void start() {
if (mSensorManager == null) {
throw new UnsupportedOperationException();
}
Sensor sensor = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (sensor == null) {
throw new UnsupportedOperationException();
}
boolean success = mSensorManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_GAME);
if (!success) {
throw new UnsupportedOperationException();
}
}

/**
* 停止搖晃檢測
*/
public void stop() {
if (mSensorManager != null)
mSensorManager.unregisterListener(this);
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}

@Override
public void onSensorChanged(SensorEvent event) {
long currentTime = System.currentTimeMillis();
long diffTime = currentTime - mLastUpdateTime;
if (diffTime < UPDATE_INTERVAL)
return;
mLastUpdateTime = currentTime;
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
float deltaX = x - mLastX;
float deltaY = y - mLastY;
float deltaZ = z - mLastZ;
mLastX = x;
mLastY = y;
mLastZ = z;
float delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ
* deltaZ)
/ diffTime * 10000;
if (delta > shakeThreshold) { // 當加速度的差值大於指定的閾值,認為這是一個搖晃
this.notifyListeners();
}
}

/**
* 當搖晃事件發生時,通知所有的listener
*/
private void notifyListeners() {
for (OnShakeListener listener : mListeners) {
listener.onShake();
}
}
}

如何使用ShakeDetector

1、new一個ShakeDetector
2、調用mShakeDetector.registerOnShakeListener()註冊一個OnShakeListener
3、在OnShakeListener的onShake函數中,處理搖晃事件
4、調用mShakeDetector.start()啟動搖晃檢測
5、mShakeDetector.stop()用於停止搖晃檢測

參考資料:
HTTP://www.clingmarks.com/?p=25
HTTP://android.hlidskialf.com/blog/code/android-shake-detection-listener
 
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()