下面的代码主要控制手机摇晃的程度,在摇晃到一定成的时候,才会触发摇一摇回调,重点在于如何保证摇一摇的触发既不能太灵敏,也不能太迟钝。
下面代码的主要思路,是计算两次时间间隔之间摇晃的空间位置之间的直线距离,从而计算获得当前时间段内摇晃手机的速度,当这个速度达到一定的阈值,则认为出发了摇一摇的动作,反之则进行下一次的摇晃数据的采集。
具体的代码如下:
代码语言:javascript复制import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import com.dragon.learn.LearnApplication;
import java.util.ArrayList;
public class ShakeUtils implements SensorEventListener {
private volatile static ShakeUtils instance;
public static ShakeUtils getInstance() {
if (instance == null) {
synchronized (ShakeUtils.class) {
if (instance == null) {
instance = new ShakeUtils();
}
}
}
return instance;
}
private ArrayList<OnShakeListener> mOnShakeListeners = null;
// 触发Shake的最小时间间隔
private static final int MIN_SHAKE_INTERVAL = 1024;
// 上次触发Shake操作的时间
private long mLastShakeTime = 0L;
private long mLastUpdateTime = 0L;
// 摇晃的速度
private static int SPEED_SHAKE_MILLSECONDS = 400;
// 两次摇晃的最小时间间隔
private static final int SHAKE_INTERVAL_MILLSECOND = 55;
// 上次摇晃的重力坐标位置
private float mLastX = 0;
private float mLastY = 0;
private float mLastZ = 0;
public interface OnShakeListener {
void onShake(double speed);
}
public ShakeUtils() {
Context context = LearnApplication.getLearnApplication();
SensorManager mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
mOnShakeListeners = new ArrayList<>();
}
public void bindShakeListener(OnShakeListener listener) {
if (listener != null) {
mOnShakeListeners.add(listener);
}
}
public void unBindShakeListener(OnShakeListener listener) {
mOnShakeListeners.remove(listener);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event == null) {
return;
}
long curUpdateTime = System.currentTimeMillis();
// 两次位置改变的时间间隔
long timeInterval = curUpdateTime - mLastUpdateTime;
if (timeInterval < SHAKE_INTERVAL_MILLSECOND) {
return;
}
if (event.values.length < 3) {
return;
}
mLastUpdateTime = curUpdateTime;
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;
double speed = Math.sqrt(deltaX * deltaX deltaY * deltaY deltaZ * deltaZ) * 1000.0 / timeInterval;
if (speed >= SPEED_SHAKE_MILLSECONDS) {
startShake(speed);
}
}
private void startShake(double speed) {
long curShakeTime = System.currentTimeMillis();
if (curShakeTime - mLastShakeTime < MIN_SHAKE_INTERVAL) {
return;
}
mLastShakeTime = curShakeTime;
for (int i = 0; i < mOnShakeListeners.size(); i ) {
mOnShakeListeners.get(i).onShake(speed);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
我们使用的时候,只需要通过bind绑定,但是需要注意在不需要shake事件的时候,需要及时的unBind:
代码语言:javascript复制import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.dragon.learn.R;
import com.dragon.learn.utils.ShakeUtils;
public class ShakeEventActionActivity extends AppCompatActivity implements ShakeUtils.OnShakeListener {
TextView mSpeedTv;
ShakeUtils mShakeUtils;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shake_event_action);
mSpeedTv = findViewById(R.id.shake_speed);
mShakeUtils = ShakeUtils.getInstance();
mShakeUtils.bindShakeListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
mShakeUtils.unBindShakeListener(this);
}
@Override
public void onShake(double speed) {
Log.e("onShake", "onShake speed:" speed);
mSpeedTv.setText("当前摇晃的速度: " speed);
}
}
摇一摇触发的效果: