11

(最後にUPDATE 3を読んでください)デバイスのセンサーと継続的に連携し、センサーと連携してデバイスの向きを取得するアプリを開発していAccelerometerますMagnetic(目的はここに記載されています)。言い換えれば、私のアプリはリアルタイムでデバイスの向きを知る必要があります(ただし、これは決して不可能なので、代わりに可能な限り高速ですが、実際には可能な限り高速です!)。Reto MeierによるプロのAndroid 4アプリケーション開発で述べられているように:

加速度計は 1 秒間に何百回も更新できます...

センサーが報告するデータを失ってはいけません。また、これらのデータに対して時間のかかる操作を実行したいと考えています (向きを取得してから計算を行います...)。を使用して問題を解決することにしましたLinkedBlockingQueue

    public void startSensors() {
            LinkedBlockingQueue<float[][]> array=new LinkedBlockingQueue();
    sensorListenerForOrientation = new SensorEventListener() {

        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
                aValues = (event.values.clone());
            else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
                mValues = (event.values.clone());
            if (aValues != null && mValues != null) {
                try {
                    array.put(new float[][] { aValues, mValues });
                } catch (InterruptedException e) {
                }
            }
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };
    Sensor aSensor = sm.getSensorList(Sensor.TYPE_ACCELEROMETER).get(
            sm.getSensorList(Sensor.TYPE_ACCELEROMETER).size() - 1);
    Sensor mSensor = sm.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).get(
            sm.getSensorList(Sensor.TYPE_MAGNETIC_FIELD).size() - 1);
    sm.registerListener(sensorListenerForOrientation, aSensor,
            SensorManager.SENSOR_DELAY_FASTEST);
    sm.registerListener(sensorListenerForOrientation, mSensor,
            SensorManager.SENSOR_DELAY_FASTEST);
    executor.execute(new Runnable() {
        @Override
        public void run() {
            doCalculations();
        }
    });
}

    public void doCalculations() {
    for (;;) {
        float[][] result = null;
        try {
            result = array.take();
        } catch (InterruptedException e) {
        }
        float[] aValues, mValues;
        aValues = result[0];
        mValues = result[1];

                    int[] degrees=getOrientation(aValues,mValues);
                    Log.e("",String.valueOf(degrees[0]));

                 //other calculations...
                     }
                                }

ここで、デバイスを手に取り、右に約 90 度回転させてから、最初の位置にすばやく (たとえば 1.5 秒で) 戻しますが、デバイスに登録されている向きを見ると、たとえば次のように表示されます: 0,1 ,2,3,4,5.......,40,39,38,37,.....,0

私が言いたいのは、結果に大きな度数のドメインが表示されないということです。私が行ったことと調査したことに基づいて、データが失われていないこと、センサーによって報告された新しいデータが記録されていることを確認できます

任意のアイデア、解決策?!

よろしく!

更新 1:デバイスで別の実験を行ったところ、衝撃的な結果が得られました! デバイスを軸上で 90 度速く (1 秒未満) 回転させると、結果にすべての角度が表示されます: 0、1、2、3、....、89、90 (たとえば)。 90 度回転させてから最初の位置に戻すと、結果は 0,1,2,...,36,37,36,...2,1,0 (たとえば)...本当に紛らわしい!

更新 2: doCalculations() メソッドを更新して、行ったことをより明確にしました

更新 3: 別の方法で問題を解決できると思います! このコードには明確な目的があります。これを見てください。何が起こるかについて述べましたが、特定の動きのジェスチャーを検出する必要があります。したがって、私が選択したすべての方法 (上記の手法) は、この問題を解決するための良い方法ではない可能性があります。おそらく、他のセンサーを使用するか、同じセンサーを別の方法で使用して、そのジェスチャーを検出する方が良いでしょう。どう思いますか?

4

7 に答える 7

2

イベント ブロック内で行う通常のことは、ほとんど何もしないことです。これは非常に高速であるためです。「ほぼ」は重要な言葉です。あなたの場合、イベントはイベントのデータを(イベントパラメータから)いくつかのデータ構造(リスト、スタック、循環バッファ...あなたの選択)に追加するだけです。そうすれば、失われるイベントが少なくなります (ある場合)。

つまり、(たとえば定期的に) 保存されたイベントを読み取り、ジェスチャが行われたかどうかを判断できます。つまり、集中的な計算が行われる頻度が少なくなります。しかし、イベントを失うことはありません。ジェスチャ認識という目的のために、これは許容できると思います。それほど高速である必要はないと思います (つまり、センサーが更新されるたびに計算する必要はありません)。

注 : これは、Linux の世界で IT を処理する一般的な方法の 1 つです。

于 2013-09-22T02:39:36.200 に答える
0

ちょっとした考え。いくつかの大きなサンプルサイズを収集して計算を実行する必要がある場合、同様の問題があります。加速が必要だったので、私の状況はおそらくあなたの状況とはかなり異なっていました。私がしたことは、配列リストを作成することでした。報告されたすべてのレコードごとに計算された加速度:

  @Override
        public void onSensorChanged(SensorEvent event) {
            float x = event.values[0];
            float y = event.values[1];
            float z = event.values[2];

            float acceleration = FloatMath.sqrt((x * x) + (y * y) + (z * z));

次に、同じ onSensorChanged メソッドで、サイズが 300 などの特定の制限に達するまで待機し、そのサンプルを新しいリストに複製し、オリジナルを消去し、新しいリストで計算を実行して、その方法で続行します。数秒で結果が得られます。アプリケーションのダウンタイムがどれくらい許容されるかはわかりませんが、これを実行すると、探しているものが 5 秒以内に取得されます。さらにサンプル コードが必要な場合はお知らせください。質問が適切に理解できていない場合は申し訳ありませんが、データをあまり失うことなく計算する方法を求めていたと思いますか? また、リスナーを登録するときに、メイン スレッドに干渉したり、ユーザー エクスペリエンスに影響を与えたりしないように、別のハンドラーでこれを実行しています。

于 2016-05-24T10:44:24.280 に答える
-1

これがあなたのコードの問題です。可能な限り高速にするには、高速なコーディング技術が必要です。センサー タイプを 2 回評価する代わりに保存します。

@Override
    public void onSensorChanged(SensorEvent event) {
        int i = event.sensor.getType();
        if (i == Sensor.TYPE_ACCELEROMETER)
            aValues = (event.values.clone());
        else if (i == Sensor.TYPE_MAGNETIC_FIELD)
            mValues = (event.values.clone());
    }
于 2013-09-20T19:41:58.353 に答える
-1
  1. 変数宣言を変更します。
List<float[][]> array = Collections.synchronizedList(new ArrayList<float[][]>());
  1. 実行可能な内部:
Iterator<float[][]> values = array.iterator();
while (values.hasNext()) {
        float[][] result = values.next();
        //calculating.

        //after calculating remove the items.
        values.remove();
}
于 2013-09-15T17:30:00.533 に答える