3

デバイスの向きを検出して、表面に逆さまに配置されているかどうかを確認し、その上でメソッドを呼び出しています。私が遭遇した問題は、ユーザーが意図せずにデバイスの向きをその位置に一瞬だけ変えて、エラーを修正するために上向きの位置に戻す可能性があるという事実ですが、メソッドは最初に実行したときにまだ呼び出されます。

ユーザーがそのメソッドがトリガーされる前に向きを修正する時間があるように、800ms の遅延で向きに「ダブルチェック」を追加しようとしています。残念ながらonSensorChanged、意図しない向きの変更を防ぐために向きを再確認する 800 ミリ秒の遅延を伴うスレッドを追加するために、 が呼び出される頻度を制御することはできません。

私のコードは次のとおりです。

public SensorEventListener accelerometerListener = new SensorEventListener(){

    @Override
    public void onSensorChanged(SensorEvent event) {

            float z_value = event.values[2];

                if (z_value < 0) {
                    //the device is now upside-down

                       try {

                           Thread.sleep(800);

                           //this if statement is never called correctly because
                           // onSensorChanged is not called again.
                                if (z_value < 0) {
                                    toggleMethod();
                                }

                        } catch (InterruptedException e) {
                               e.printStackTrace();
                        }
                 }
          }

私の質問:onSensorChanged二重チェックを実行するために、onSensorChanged メソッド自体の中で遅延を呼び出す方法はありますか?

4

3 に答える 3

2

onSensorCheck を使用するときに行う最善の方法は、フィルターを使用することです。常に、センサーによって与えられた n 個の最後の値の平均を決定します。この方法により、アプリはスムーズに動作し、突然のセンサーの変化は影響しません。
方法は次のとおりです。

z_value = 0.2*event.values[2]+0.8*z_value; // 0.2+0.8 = 1 

この方法では、新しい値の 20% のみを取得し、残りは最後の 4 つの値の平均になります。

結果に満足するまで、coefs をいじってみてください。

私にとって、これは非常にうまくいきました:

 z_value = 0.02*event.values[2]+0.98*z_value;

---------------------------------------------------------------

編集

z_value を初期化する方法は次のとおりです。 z_value はフィールドである必要があります。初期化、つまり最初の onSensorChanged 呼び出しにのみ使用される別のブール値フィールドを追加する必要があります。したがって、2 つのフィールドがあります。

double z_value =0;
boolean firstTime = true;

ここに onSensorChanged メソッドがあります:

@Override
public void onSensorChanged(SensorEvent event) {
        if(firstTime){
            z_value = event.values[2]; // you will enter here only the first time
            firstTime = false
        }
        else{
            z_value = 0.02*event.values[2] + 0.98*z_value;
        }

        if (z_value < 0) {
                //the device is now upside-down

               // do what you gotta do
        }
 }
于 2013-09-20T21:31:57.607 に答える
0

もう 1 つのアプローチは、時間の経過とともに入力を平滑化することです。そのため、800 ミリ秒の入力の平均読み取り値を取得します。

(YAT の応答は正しい考えを持っていますが、実行は実際には時間の経過とともに配信されるサンプルの量を考慮していません。これは、1 つの電話から次の電話まで不明です。また、測定値を決して忘れません。10 秒後の動作は1 分後には大幅に異なります。)

//the idea here is to store all the inputs over the last 800ms and average them
LinkedList<Entry<long, double>> inputs = new LinkedList<Entry<long,double>>
double totalZ = 0.0f;   //keep a running total so we don't have to iterate through the list to calculate the average

@Override
public void onSensorChanged(SensorEvent event) {
    //clear out values older than 800ms
    while(inputs.size() > 0 && inputs.getLast().getKey() < System.currentTimeInMillis() - 800){
        Entry<long, double> deletedEntry = inputs.removeLast();
        totalZ -= deletedEntry.getValue(); //update the running total
    }

    //add the new measurement to the head
    inputs.addFirst(new Entry<long, double>(System.currentTimeInMillis(),event.values[2]));
    totalZ += event.values[2]; //update the running total with the new measurement

    //this is the Z averaged over 800ms
    float averagedZ = totalZ / inputs.size();
}

または、最初の変更の検出時に、尋ねられている質問に沿った、より単純なアプローチ。

時間を節約し、新しい潜在的な状態を保存します

次に、別の onSensorChanged() を取得すると

その状態は潜在的な状態と同じですか?そうでない場合は、時間をクリアして電位状態をクリアします

800ms が経過し、潜在的な状態がまだ現在の状態である場合は、その変更を開始します。

onSensorChanged はほとんどの精度モードで 1 秒間に何度も呼び出されるため、通常の onSensorChanged 呼び出しが発生するのを待つだけで 800 ミリ秒近くになるはずです。

以下の大まかな疑似コード

long lastChange = 0;
int potentialState = 0;

@Override
public void onSensorChanged(SensorEvent event) {
    int currentState = determineCurrentState(event); //whatever your logic is and states

    if(potentialState != currentState){
         lastChange = System.currentTimeInMillis();
         potentialState = currentState;
    }
    else if(lastChange + 800 < System.currentTimeInMillis()){
         //execute state change, 800ms have elapses with no further change in state
         stateChange(currentState);
    }
于 2013-09-23T15:51:16.290 に答える