Androidスマートフォンからセンサー測定値を収集します。 エラー処理

以前の投稿で、 3つの平面すべてでデバイスの傾斜角を取得する方法について説明しました。 ただし、判明したように、トピックで使用されているメソッド 、APIレベル8(Android 2.2)から廃止されています。 このエラーを修正し、カットの下でデータを正しく受信する方法を説明します。

まず、少しの理論


Androidのドキュメントでは、SENSOR_ORIENTATIONの代わりにメソッドを使用するように提供されています
getOrientation (float[] R, float[] values) 

このメソッドは2つのパラメーターを取ります。

したがって、目標を達成するには、まさに回転行列を取得する必要があります。 そして、あなたは別の方法からそれを得ることができます:
 getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic) 

最初の2つの配列のこのメソッドは、(地球の磁極?)からのデバイスの回転行列と偏差行列を配置します。 これを行うには、加速度センサーと地磁気センサーからデータを転送する必要もあります。 幸いなことに、TYPE_ACCELEROMETERとTYPE_MAGNETIC_FIELDは非推奨ではありません。 したがって、私たちは彼らから証言を取ります。

練習に移りましょう


前の例と同じレイアウトを取ることができます。 ここにあります:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <LinearLayout android:id="@+id/linearLayout1" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView1" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text=" XY" /> <TextView android:id="@+id/xyValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text="0" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout2" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView3" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text=" XZ" /> /> <TextView android:id="@+id/xzValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text="0" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout3" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView5" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text=" ZY" /> <TextView android:id="@+id/zyValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="25dp" android:text="0" /> </LinearLayout> </LinearLayout> 


メインアクティビティで、変数を宣言します。

  private final SensorManager msensorManager; //   private float[] rotationMatrix; //  private float[] accelData; //   private float[] magnetData; //   private float[] OrientationData; //    private TextView xyView; private TextView xzView; private TextView zyView; 


onCreateメソッドは、SensorEventListenerクラスのメソッドを実装する必要があるため、その宣言は変更されます。

  public class Main extends Activity implements SensorEventListener{ 

また、2つの必須メソッドonAccuracyChangedおよびonSensorChangedが追加されます。
そして、 setContentViewの前に次のように記述します。

  msensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); rotationMatrix = new float[16]; accelData = new float[3]; magnetData = new float[3]; OrientationData = new float[3]; xyView = (TextView) findViewById(R.id.xyValue); // xzView = (TextView) findViewById(R.id.xzValue); //       zyView = (TextView) findViewById(R.id.zyValue); // 


私の最後の投稿を読んだ場合、新しいものは何も見ていません。 そうでない場合は、最初の行でセンサーマネージャーのオブジェクトを取得することを知っておく必要があります。
次に、必要なセンサーデータを明確にするonResumeメソッドを作成します。

  @Override protected void onResume() { super.onResume(); msensorManager.registerListener(this, msensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI ); msensorManager.registerListener(this, msensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI ); } 

ここで、registerListenerメソッドに、必要なセンサーのタイプ( センサー指定の完全なリスト )とデータ更新の頻度(SENSOR_DELAY_NORMAL、SENSOR_DELAY_UI、SENSOR_DELAY_GAME、またはSENSOR_DELAY_FASTESTの頻度が高い順)を渡します。

プログラムがスマートフォンのリソースを使い果たしないように、onPauseイベントによって最小化され、センサーからデータを「削除」します。

  @Override protected void onPause() { super.onPause(); msensorManager.unregisterListener(this); } 


センサーからのデータがセンサーに対応する配列に入力される新しいメソッドを作成しましょう。 loadNewSensorDataメソッドを呼び出します。

  private void loadNewSensorData(SensorEvent event) { final int type = event.sensor.getType(); //   if (type == Sensor.TYPE_ACCELEROMETER) { //  accelData = event.values.clone(); } if (type == Sensor.TYPE_MAGNETIC_FIELD) { //   magnetData = event.values.clone(); } } 

まあ、それはほとんどそれです! onSensorChangedイベントハンドラを記述するだけです。

  public void onSensorChanged(SensorEvent event) { loadNewSensorData(event); //     SensorManager.getRotationMatrix(rotationMatrix, null, accelData, magnetData); //   SensorManager.getOrientation(rotationMatrix, OrientationData); //      if((xyView==null)||(xzView==null)||(zyView==null)){ //   . xyView = (TextView) findViewById(R.id.xyValue); xzView = (TextView) findViewById(R.id.xzValue); zyView = (TextView) findViewById(R.id.zyValue); } //  xyView.setText(String.valueOf(Math.round(Math.toDegrees(OrientationData[0])))); xzView.setText(String.valueOf(Math.round(Math.toDegrees(OrientationData[1])))); zyView.setText(String.valueOf(Math.round(Math.toDegrees(OrientationData[2])))); } 


すべて準備完了です! 今、私は間違いを訂正し、非推奨ではない方法でセンサーからデータを受信する方法を教えました。 :)

結論として、 ソース完成したapk 、および情報源へのリンクを提供します。

PS:あなたはおそらく最後のリストのヌルとは対照的に、変数の余分なチェックに気づいたでしょう。 これがないと、コンパイラはjava.lang.NullPointerExceptionをスローします。 誰かがエラーを説明したり指摘したりしてくれたらありがたいです。

UPD: firexelのおかげで問題は解決しました
onCreateのfindViewByIdでsetContentViewと行を交換します

その後、余分なチェックを削除できます。

Source: https://habr.com/ru/post/J137820/


All Articles