Android实现摇一摇触发逻辑

2021-04-22 11:28:49 浏览数 (1)

下面的代码主要控制手机摇晃的程度,在摇晃到一定成的时候,才会触发摇一摇回调,重点在于如何保证摇一摇的触发既不能太灵敏,也不能太迟钝。

下面代码的主要思路,是计算两次时间间隔之间摇晃的空间位置之间的直线距离,从而计算获得当前时间段内摇晃手机的速度,当这个速度达到一定的阈值,则认为出发了摇一摇的动作,反之则进行下一次的摇晃数据的采集。

具体的代码如下:

代码语言: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);
    }
}

摇一摇触发的效果:

0 人点赞