要想實現指南針功能,其實主要就是獲取手機的方位,通過對比前一刻方位和現在手機方位算出手機旋轉的角度,然后根據手機實際旋轉的角度去旋轉指南針的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 方向角,但用(磁場+加速度)得到的數據范圍是(-180~180),也就是說,0表示正北,90表示正東,180/-180表示正南,-90表示正西。而直接通過方向感應器數據范圍是(0~359)360/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]);
}};
