SensorManager的方向感測器Orientation -- 指南針的簡易實現
通過SensorManager獲取手機方位,從而實現指南針功能。
在很多舊的文件介紹中,都是通過SensorManager .getDefaultSensor(Sensor.TYPE_ORIENTATION); 但是,這個方法其實是已經被android拋棄的方法,現在我們來講一下新的方法。
一 首先我們需要認識到在手機裡是沒有方位感測器這個實體的硬體,它只是通過一些邏輯運算而計算出來的。而它是通過磁場感測器和加速度感測器計算得來的。
二 實現方法,註冊磁場感測器和加速度感測器監聽,在監聽中獲取加速度感測器的Values值和磁場感測器的Values值,根據這倆個值計算方位感測器的value
三 通過SensorManager類的倆個重要方法:getRotationMatrix()和getOrientation()方法獲取方位感測器的value。
booleangetRotationMatrix(float[] R, float[] I, float[] gravity, float[] geomagnetic)
float[]getOrientation(float[] R, float[] values)
在getRotationMatrix()方法中, float[] R是輸出值,I/gravity/geomagnetic是輸入值。
通過float[] I為null,float[] gravity在onSensorChanged()中從加速度感測器中獲取,float[] geomagenetic在onSensorChanged()中從磁場感測器中獲取。
在getOrientation()方法中,float[] R是輸入值,float[] values是輸出值,該值就是方位感測器的value值。該值介紹請看下文四。
四 方位感測器的value值是個float[3]陣列,
其中values[0]表示手機頂部和正北方的夾角,0表示手機頂部朝向正北,90表示手機頂部朝向正東,180表示手機頂部朝向正南,-90表示手機頂部朝向正西。
values[1]表示手機頂部或尾部翹起的角度。水平放置該值是0。
values[2]表示手機左側或右側翹起的角度。水平放置該值是0;
其實我們在指南針的實現中,只用到了values[0]的值。
最後我們看一下完整的程式碼:
public class MainActivity extends Activity { private static final String TAG ="LinkGame: MainActivity"; private SensorManager mSensorManager =null; private Sensor mAcceleSensor = null; private Sensor mMagneticSensor = null; private float targetDegree =0.0f; private MyCompassView mImageView; private boolean mStopUpdateCompass; private float[] mMageneticValues = new float[3]; private float[] mAcceleValues = new float[3]; @Override protected void onCreate(Bundle savedInstanceState) { Log.d(TAG," onCreate() ysj"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initCompass(); } public void initCompass(){ Log.d(TAG," initCompass()"); mImageView = (MyCompassView)findViewById(R.id.compass_image); mSensorManager = (SensorManager) this.getSystemService(this.SENSOR_SERVICE); mAcceleSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mMagneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); Log.d(TAG," onResume() ysj targetDegree ="+targetDegree); mStopUpdateCompass = false; mSensorManager.registerListener(mOrientationSensorEventListener,mAcceleSensor , SensorManager.SENSOR_DELAY_NORMAL); //註冊加速度感測器監聽 mSensorManager.registerListener(mOrientationSensorEventListener,mMagneticSensor , SensorManager.SENSOR_DELAY_NORMAL);//註冊磁場感測器監聽 new Handler().postDelayed(mRunnable, 100); } private Runnable mRunnable = new Runnable(){ @Override public void run() { // TODO Auto-generated method stub if(mImageView != null && mStopUpdateCompass == false){ Log.d(TAG," mImageView().updateCompass: targetDegree ="+targetDegree); mImageView.updateCompass(targetDegree); new Handler().postDelayed(mRunnable, 500); } } }; @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); Log.d(TAG," onPause() ysj"); mStopUpdateCompass = true; mSensorManager.unregisterListener(mOrientationSensorEventListener); } @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); Log.d(TAG," onStop() ysj"); mStopUpdateCompass = true; mSensorManager.unregisterListener(mOrientationSensorEventListener); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.d(TAG," onDestroy() ysj"); } private SensorEventListener mOrientationSensorEventListener = new SensorEventListener(){ @Override public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub Log.d(TAG," onAccuracyChanged()"); } @Override public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub int sensorType = event.sensor.getType(); Log.d(TAG," onSensorChanged() sensorType = "+sensorType); //通過加速度感測器的mAcceleValues和磁場感測器的mMageneticValues,來計算方位感測器的value if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){ mAcceleValues = event.values; } if(event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){ mMageneticValues = event.values; } calculateOrientation(); } }; public void calculateOrientation(){ float[] values = new float[3]; float[] R = new float[9]; SensorManager.getRotationMatrix(R, null, mAcceleValues, mMageneticValues); SensorManager.getOrientation(R, values); values[0] = (float)Math.toDegrees(values[0]); Log.d(TAG," calculateOrientation() values[0]="+values[0] ); targetDegree = (-values[0]+360.0f) % 360; } }