Android指南針app的實現原理總結


要想實現指南針功能,其實主要就是獲取手機的方位,通過對比前一刻方位和現在手機方位算出手機旋轉的角度,然后根據手機實際旋轉的角度去旋轉指南針的imageview。關鍵在於如何獲取手機實際方位。

那么如何獲取到這個方位呢?


那么,android中不是有方向傳感器嗎?其實android 的方向傳感器不是物理實際存在的,它只是邏輯上的,什么意思,就是它是通過磁力計和加速度計抽象出來的。因此,這個方位的獲得其實是通過這兩個傳感器的數 據通過一定的算法得到的。而這個算法則封裝在了api中,我們只需直接使用即可。

一般情況下,在android系統中獲取手機的方位信息azimuth似乎是很簡單的事情,在api中有 TYPE_ORIENTATION常量,可以像得到加速度傳感器那樣得到方向傳感器 sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);然而我們這樣做的話在最新版的SDK中就會看到這么一句 話:“TYPE_ORIENTATION   This constant is deprecated. use SensorManager.getOrientation() instead. ”即這種方式也過期,不建議使用!Google建議我們在應用程序中使用SensorManager.getOrientation()來獲得原始數據。

那么我們來看一下這個getOriention的用法。

先看看器定義:

public static float[] getOrientation (float[] R, float[] values)

第一個參數是R[] 是一個旋轉矩陣,用來保存磁場和加速度的數據,可以理解為這個函數的傳入值,通過它這個函數給你求出方位角。

第二個參數就是這個函數的輸出了,他有函數自動為我們填充,這就是我們想要的。

 

values[0]  :azimuth 方向角,但用(磁場+加速度)得到的數據范圍是(-180180,也就是說,0表示正北,90表示正東,180/-180表示正南,-90表示正西。而直接通過方向感應器數據范圍是(0359360/0表示正北,90表示正東,180表示正南,270表示正西。

values[1]  pitch 傾斜  即由靜止狀態開始,前后翻轉

values[2]  roll 旋轉角 即由靜止狀態開始,左右翻轉

 


現在問題是這個R[]怎么獲取,其實他是通過函數getRotationMatrix得到的。

看看getRotationMatrix的定義:

 

public static boolean getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic)

解釋以下參數,第一個就是我們需要填充的R數組,大小是9

                            第二個是是一個轉換矩陣,將磁場數據轉換進實際的重力坐標中 一般默認情況下可以設置為null

                            第三個是一個大小為3的數組,表示從加速度感應器獲取來的數據  在onSensorChanged中

                            第四個是一個大小為3的數組,表示從磁場感應器獲取來的數據    在onSensorChanged中


實例代碼:

public class OrientationActivity extends Activity {    
    /** Called when the activity is first created. */    
    TextView textview=null;    
    private SensorManager sm=null;    
    private Sensor aSensor=null;    
    private Sensor mSensor=null;    
         
    float[] accelerometerValues=new float[3];    
    float[] magneticFieldValues=new float[3];    
    float[] values=new float[3];    
    float[] R=new float[9];    
        
    @Override    
    public void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.main);    
        textview=(TextView)findViewById(R.id.view_main);    
        sm=(SensorManager)getSystemService(Context.SENSOR_SERVICE);    
        aSensor=sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);    
        mSensor=sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);    
        sm.registerListener(myListener, aSensor, SensorManager.SENSOR_DELAY_GAME);    
        sm.registerListener(myListener, mSensor, SensorManager.SENSOR_DELAY_GAME);   
            
    }    
    
    @Override  
  //注意activity暫停的時候釋放   
    protected void onPause() {    
        // TODO Auto-generated method stub    
        super.onPause();    
        sm.unregisterListener(myListener);    
    }    
    final SensorEventListener myListener=new SensorEventListener(){    
    
        @Override    
        public void onAccuracyChanged(Sensor sensor, int accuracy) {    
            // TODO Auto-generated method stub    
                
        }    
    
        @Override    
        public void onSensorChanged(SensorEvent event) {    
            // TODO Auto-generated method stub    
            if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){    
                accelerometerValues=event.values;    
            }    
            if(event.sensor.getType()==Sensor.TYPE_MAGNETIC_FIELD){    
                magneticFieldValues=event.values;    
            }    
            //調用getRotaionMatrix獲得變換矩陣R[]    
            SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues);    
            SensorManager.getOrientation(R, values);    
            //經過SensorManager.getOrientation(R, values);得到的values值為弧度    
            //轉換為角度    
            values[0]=(float)Math.toDegrees(values[0]);    
            textview.setText("x="+values[0]);    
        }};    

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM