OnSensorChanged вызывается чаще, чем предполагалось

avatar
Y. M
8 апреля 2018 в 03:43
544
1
3

Я пытаюсь разработать приложение, которое обнаруживает падение, и пока что точность падения находится в приемлемом диапазоне, но проблема в том, что "OnSensorChanged" вызывается слишком часто, из-за чего всплывающее уведомление постоянно появляется на моем экране. .

Я думаю, что проблема в том, что во время свободного падения "OnSensorChanged" продолжает вызываться на протяжении всего падения (поскольку значения соответствуют падению), что и вызывает спам всплывающих уведомлений на моем экране.

Решение, которое я пробовал, состоит в том, чтобы отменить регистрацию слушателя после падения, чтобы он появлялся только один раз, но проблема в том, что он не обнаружит падение снова, пока я не перезапущу приложение (потому что, очевидно, слушатель перестал работать).

Есть ли решение этой проблемы? Спасибо

private void checkFall(SensorEvent xyzValues) {
    float[] values = xyzValues.values;
    double rootSquare = Math.sqrt(Math.pow(values[0],2)+Math.pow(values[1],2)+Math.pow(values[2],2));

        if (rootSquare < 1.5){

            Toast toast = Toast.makeText(this, "The Phone Fell!", Toast.LENGTH_LONG);
            toast.show();
            sensorManager.unregisterListener(this);
            sensorManager = null;


        }
public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        checkFall(event);

    }
}
Источник

Ответы (1)

avatar
Cvarier
8 апреля 2018 в 06:37
2

Вы можете использовать логическую переменную-член mFallen, которая отслеживает, когда только что произошло падение. Вы также можете определить некоторое пороговое значение, чтобы указать, когда телефон возвращается в нормальное «стоящее» состояние. Попробуйте следующее:

    if (rootSquare < 1.5 && !mFallen){
        Toast toast = Toast.makeText(this, "The Phone Fell!", Toast.LENGTH_LONG);
        toast.show();
        mFallen = true;
    } else if (rootSquare > STANDING_THRESHOLD) {
        mFallen = false;
    }

Улучшенный алгоритм обнаружения стояния

После того, как состояние mFallen изменилось с ложного на истинное, величина вектора ускорения устройства (вычисленная и сохраненная в rootSquare) должна быть очень близка к 0. Это связано с тем, что когда устройство находится в при свободном падении (падении само по себе) его ускорение будет равно ускорению силы тяжести в системе отсчета стоящего человека. Но теоретически акселерометр будет измерять значения только относительно свободного падения, и поэтому он будет точно равен 0.

Поскольку ускорение свободного падения составляет примерно 9,81 м/с^2, чтобы определить, когда устройство снова не движется, вам нужно проверить, когда величина ускорения близка к этому. Это связано с тем, что в неподвижном состоянии датчик будет обнаруживать силу, которая препятствует его падению (отменяя ускорение из-за силы тяжести), которая является силой того, что удерживает его на месте. В этом случае общая величина ускорений, вызванных этими силами, должна в точности равняться величине ускорения свободного падения.

Вы можете определить константу GRAVITY как 9.81, а GRAVITY_THRESHOLD как значение допуска, которое вы можете попробовать установить на 0.1, а затем уточнить позже. Попробуйте заменить свой код следующим:

if (rootSquare < 1.5 && !mFallen){
    Toast toast = Toast.makeText(this, "The Phone Fell!", Toast.LENGTH_LONG);
    toast.show();
    mFallen = true;
} else if (Math.abs(rootSquare - GRAVITY) < GRAVITY_THRESHOLD) {
    mFallen = false;
}

Просто подчеркнем, что стоячее состояние здесь определяется как только когда устройство перестало двигаться, поэтому оно не сможет определить, когда телефон достиг определенной высоты относительно земли. .

Пожалуйста, см. https://developer.android.com/reference/android/hardware/SensorEvent.html#values, так как это может помочь вам лучше понять проблему.

Y. M
8 апреля 2018 в 07:12
0

Спасибо!! Кажется, это имеет смысл и должно работать, попробую, когда буду дома, и сообщу о результатах: D

Cvarier
8 апреля 2018 в 07:23
0

Нет проблем, и я просто обновил код для большей читабельности. Кстати, убедитесь, что вы инициализируете mFallen значением false.

Y. M
11 апреля 2018 в 12:23
0

Извините, по какой-то причине мой комментарий не был опубликован :( .. Проблема в том, что я не мог найти постоянный порог (ближайшим был тот, который запускал метод 2-3), поэтому я решил просто сопоставить логическое значение (mFallen) с кнопка, щелчок по которой снова включит обнаружение падения.. Итак, на данный момент пользователь должен вручную повторно включить обнаружение падения, поскольку оно будет отключено при первом вызове метода.Однако ваше предложение по-прежнему является основной идеей, поэтому спасибо: )

Y. M
11 апреля 2018 в 12:25
0

Еще одна вещь, комментарий, который не был опубликован, меня смутил, почему он срабатывал 2-4 раза: D

Cvarier
11 апреля 2018 в 18:40
0

Определенно есть способ сделать это лучше, чем повторное включение слушателя :) На самом деле, вы должны видеть, что onSensorChanged() вызывается несколько раз, так как он постоянно проверяет изменения значений датчика, и некоторые из них могут быть пиками. Пожалуйста, смотрите мой обновленный ответ для лучшего алгоритма обнаружения постоянного.

Cvarier
18 апреля 2018 в 04:15
0

@ Y.M Эй, прошла уже неделя, помог ли мой обновленный ответ?

Y. M
20 апреля 2018 в 15:45
0

Здравствуйте, извините за поздний ответ. Это, безусловно, помогло, но мне нужно время, чтобы проверить разные значения, пока я не достигну идеального порога (где метод не будет вызываться более одного раза)