5

これは、ここで私の質問へのフォローです:Android thread runnable performanceAndroid同期onSensorChanged?

私はいくつかの困難私のアプリ

ための同期方法のまわりで私の頭をラップを抱えている私は、ポーリングセンサーだといつでも彼ら配列にセンサ値を格納変更

float[] accelerometerMatrix = new float[3]; 
float[] accelerometerWorldMatrix = new float[3]; 
float[] gyroscopeMatrix = new float[3]; 
float[] gravityMatrix = new float[3]; 
float[] magneticMatrix = new float[3]; 
float[] rotationMatrix = new float[9]; 

class InsertHandler implements Runnable { 
     public void run() { 
      //get values from arrays and insert into db 
     } 
    } 

public void onSensorChanged(SensorEvent event) { 
     sensor = event.sensor; 

     int i = sensor.getType(); 
     if (i == MainActivity.TYPE_ACCELEROMETER) { 
      accelerometerMatrix = event.values; 
     } else if (i == MainActivity.TYPE_GYROSCOPE) { 
      gyroscopeMatrix = event.values; 
     } else if (i == MainActivity.TYPE_GRAVITY) { 
      gravityMatrix = event.values; 
     } else if (i == MainActivity.TYPE_MAGNETIC) { 
      magneticMatrix = event.values; 
     } 

     long curTime = System.currentTimeMillis(); 
     long diffTime = (curTime - lastUpdate); 

     // only allow one update every POLL_FREQUENCY. 
     if(diffTime > POLL_FREQUENCY) { 
      lastUpdate = curTime; 

      //insert into database in background thread 
      executor.execute(insertHandler); 
     } 
    } 

10msごとに、私のアプリは現在のセンサー値(配列から)をとり、単一のスレッドエグゼキュータを使用してデータベースに挿入します。したがって、onSensorChangedメソッドは、配列への書き込みと、配列からデータベースへの書き込みの両方を行うことです。

私の質問は、onSensorChangedメソッドを同期する必要がありますか?

最も重要なことは、私はすべてのデータを見逃さないということです。 10msごとに、現在のセンサー値を保存する必要があります。何も見逃すことはありません。

だから私の理解に、同期メソッドはUIスレッドがロックを保持し、それが配列へのセンサーの値を書き込むことを意味します。この間、executorスレッドは、ロックのためにそれらの配列から読み取ることができません。次に、ロックが解除され、エグゼキュータスレッドがロックされ、配列から読み込み、データベースに書き込むとロックが解除されます。

ここで同期メソッドの使用を誤解している可能性があります。それはそれ

に果たしている。しかし、このような状況で、私は10ms毎に最新の値を挿入していない可能性がありますようですか。 UIスレッドがロックを確立すると、エグゼキュータスレッドはそれらの値をデータベースに書き込むことができません。エグゼキュータスレッドが書き込むことができる時間までに、値は数msになり、不正確になります。

一方、同期では、UIスレッドが配列値を変更している状況はありません。エグゼキュータスレッドがデータベースに変更した値の半分を挿入すると同時に

最新の/正確なセンサーデータを10msごとに挿入する必要があるこの種の状況では、同期メソッドを使用する必要がありますか? Runnableは、UIスレッドがへの書き込みをされているのと同じ配列を使用しているよう

答えて

2

あなたの現在のコードはスレッドセーフではありません。あなたがexecutor.execute(insertHandler);をコールすると、UIスレッドが別のセンサイベントを取得し、Runnableをデータベースに書き込む前に、配列の値のいずれかを変更しないという保証はありません。あなたはこの部分を理解しているようです。

これを修正するには、diffTime > POLL_FREQUENCYの配列に格納されている値を書き出すだけで、同期ブロックを使用することはお勧めできません。 onSensorChanged(...)メソッド自体はコード内のUIスレッドでのみ呼び出されるため、このメソッドで配列の値を変更する別のスレッドについて心配する必要はありません。

あなたのできることは、配列の現在の値をRunnableクラスの新しいインスタンスに保存することです。以前の投稿では同じインスタンスを使用するように提案されていましたが、目立った違いはありません。 Android Monitorを開いてアプリケーションを実行することでメモリ使用量を確認することによっても確認できます。現在の値を保存することで、変更しないで必要なデータのコピーを既に持っているので、データを書き出す前にonSensorChanged()が再度呼び出された場合は問題になりません。

class InsertHandler implements Runnable { 
    final float[] accelerometerMatrix; 
    final float[] accelerometerWorldMatrix; 
    final float[] gyroscopeMatrix; 
    final float[] gravityMatrix; 
    final float[] magneticMatrix; 
    final float[] rotationMatrix; 

    public InsertHandler(float[] accelerometerMatrix, float[] accelerometerWorldMatrix, 
      float[] gyroscopeMatrix, float[] gravityMatrix, 
      float[] magneticMatrix, float[] rotationMatrix) { 
     this.accelerometerMatrix = accelerometerMatrix; 
     this.accelerometerWorldMatrix = accelerometerWorldMatrix; 
     this.gyroscopeMatrix = gyroscopeMatrix; 
     this.gravityMatrix = gravityMatrix; 
     this.magneticMatrix = magneticMatrix; 
     this.rotationMatrix = rotationMatrix; 
    } 

    public void run() { 
     // use class field arrays values and insert into db 
    } 
} 

をそしてあなたはexecutor使用にRunnableを追加するとき:

Runnable insertHandler = new InsertHandler(accelerometerMatrix, accelerometerWorldMatrix, 
     gyroscopeMatrix, gravityMatrix, magneticMatrix, rotationMatrix); 
executor.execute(insertHandler); 
ここ

は、私がコードで示唆されていますものです
関連する問題