位置感應器

Android 平台提供兩種感應器,可讓您判斷位置 地理磁場感應器和加速計Android 平台也提供感應器,可讓您判斷 裝置對應至物件 (稱為「鄰近感應器」)。 地磁場感應器與鄰近感應器採用硬體。大多數 手機和平板電腦製造商包含一個地磁場感應器。同樣地 手機製造商通常會提供鄰近感應器,藉此判斷 手機貼近使用者臉部 (例如使用手機時) 呼叫)。若要判斷裝置的螢幕方向,可以使用以下來源的讀數: 裝置加速計和地磁場感應器。

注意:方向感應器已在 Android 2.2 版中淘汰 (API 級別 8) 和方向感應器類型已於 Android 4.4W 淘汰 (API 級別 20)。

位置感應器可用於判斷裝置在以下位置的實際位置: 全世界的參考架構例如,您可以使用「Geomagnetic」欄位 感應器,結合加速計來判斷裝置的位置 以及磁鐵的相對基準您也可以使用這些感應器 在應用程式參考的畫面中判斷裝置的螢幕方向。 位置感應器通常不用於監控裝置的動作或動作。 例如搖動、傾斜或推彎 (詳情請參閱「動作感應器」)。

地磁場感應器和加速計會傳回多維陣列 各 SensorEvent 的感應器值。例如: 地磁場感應器提供地磁場強度值 在單一感應器事件發生時,每個座標軸代表一個軸。同樣地, 加速計感應器會測量在 也就是感應器事件如要進一步瞭解使用的座標系統 依感測器計算,請參閱 感應器座標系統。鄰近感應器提供單一值 每項感應器事件的資料表 1 摘要列出 Android 平台支援功能。

表 1. Android 平台支援的位置感應器。

感應器 感應器事件資料 說明 測量單位
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] 沿著 X 軸的旋轉向量元件 (x * sin(while/2))。 無單位
SensorEvent.values[1] 沿著 Y 軸的旋轉向量元件 (y * sin(while/2))。
SensorEvent.values[2] 沿著 Z 軸的旋轉向量元件 (z * sin(while/2))。
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] 沿著 X 軸的旋轉向量元件 (x * sin(while/2))。 無單位
SensorEvent.values[1] 沿著 Y 軸的旋轉向量元件 (y * sin(while/2))。
SensorEvent.values[2] 沿著 Z 軸的旋轉向量元件 (z * sin(while/2))。
TYPE_MAGNETIC_FIELD SensorEvent.values[0] 沿著 X 軸的地磁場強度。 微特
SensorEvent.values[1] Y 軸的地磁場強度。
SensorEvent.values[2] 沿著 Z 軸的地磁場強度。
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] 沿著 X 軸的地磁場強度 (沒有硬鐵校正)。 微特
SensorEvent.values[1] Y 軸的地磁場強度 (沒有硬鐵校正)。
SensorEvent.values[2] 沿著 Z 軸的地磁場強度 (沒有硬鐵校正)。
SensorEvent.values[3] 沿著 X 軸推測出的鐵偏誤。
SensorEvent.values[4] Y 軸上的鐵偏誤。
SensorEvent.values[5] 沿著 Z 軸推測出的鐵偏誤。
TYPE_ORIENTATION1 SensorEvent.values[0] 方位角 (Z 軸的角度)。
SensorEvent.values[1] 俯仰角 (X 軸周圍的角度)。
SensorEvent.values[2] 旋轉 (Y 軸周圍的角度)。
TYPE_PROXIMITY SensorEvent.values[0] 與物體的距離2 公分

1這個感應器已在 Android 2.2 (API) 中淘汰 第 8 級),而且這個感應器類型已在 Android 4.4W (API 級別 20) 中淘汰。 感應器架構提供替代方法, 請參閱 Compute 裝置的螢幕方向

2 部分鄰近感應器只會提供二進位值 代表距離非常遠近

使用遊戲旋轉向量感應器

遊戲旋轉向量感應器與 旋轉 向量感應器,但不會使用地磁場。因此 Y 軸不會 而是指向其他參考來源參照的參照可以 與陀螺儀環繞 Z 軸的規模大小相同。

因為遊戲旋轉向量感應器不會使用磁場,所以相對旋轉 ,不受磁場變更的影響。如果符合以下情況,就能在遊戲中使用這個感應器: 不必在意北方的位置,而一般的旋轉向量不符合您的需求 因為這個結構仰賴磁場。

以下程式碼說明如何取得預設遊戲旋轉向量的執行個體 感應器:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);

使用地磁旋轉向量感應器

地質旋轉向量感應器與 旋轉向量感應器 而且不會使用陀螺儀。這個感應器的準確度低於一般旋轉向量 但耗電量會降低只有在想收集旋轉資訊時,才需要使用這個感應器 並減少耗電量。這個感應器在使用時機最為實用 搭配批次處理

以下程式碼顯示如何取得預設地磁旋轉值的執行個體 向量感應器:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);

計算裝置螢幕方向

計算裝置方向,即可監控 則是相對於地球參考框 (具體來說 北極旗標)。以下程式碼顯示如何計算裝置的 方向:

Kotlin

private lateinit var sensorManager: SensorManager
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading)

// Express the updated rotation matrix as three orientation angles.
val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles)

Java

private SensorManager sensorManager;
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null,
    accelerometerReading, magnetometerReading);

// Express the updated rotation matrix as three orientation angles.
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);

系統使用裝置的地磁性計算方向角度 現場感應器與裝置的加速計結合。使用這兩個 硬體感應器可提供以下三個 方向角度:

  • 方位角 (-z 軸的旋轉角度)。這是 裝置目前指南針方向與磁北之間的角度。 如果裝置的上緣面向磁性,,方位角度為 0 度;如果頂部邊緣朝南,方位角度為 180 度。同樣地 如果上方邊緣朝東面,方位角為 90 度,如果上緣 面向西部的面向,方位角度為 270 度。
  • 音高 (X 軸旋轉角度)。這是 平面與裝置螢幕平行的平面之間 傳送到地面。如果將裝置與地面平行並貼合底部 並將裝置的頂端邊緣往地面傾斜 傾斜角度變為正值相反地, 將裝置的頂部邊緣與地面移開,會造成問題 將傾斜角度變為負數將介於 90 度。
  • 旋轉 (Y 軸旋轉角度)。這是 平面與裝置螢幕垂直的角度 與地面垂直。如果手持裝置與地面平行 並將螢幕左下邊緣設為離您最近的邊緣,並傾斜裝置左側邊緣。 轉向地面時,擲出的角度就會變成正。對面則傾斜 方向—將裝置的右側邊緣朝向地面 — 會導致擲骰角度變為負數。值的範圍是 -180 度 溫度設為 180 度

注意:感應器的轉動定義已根據 地理感應器生態系統中的絕大多數的實作方式。

請注意,這些角度的運作方式,使用的座標系統不同於 一個用於航空的飛行 (右轉、俯仰和滾動)。在航空系統中, X 軸沿著平面的長邊 (從尾到鼻子) 長。

方向感應器透過處理原始感應器資料來取得資料 以及地磁場感應器由於 以及螢幕方向的準確性和精確度 感應器就會變暗。具體來說,這個感應器只有在擲骰子時才能運作 角度為 0。因此,Android 已淘汰方向感應器 2.2 (API 級別 8),且 Android 中的方向感應器類型已淘汰 4.4W (API 級別 20)。 建議您不要使用方向感應器的原始資料, 使用getRotationMatrix() 方法搭配 getOrientation() 種方式 計算方向值,如下列程式碼範例所示。裝置 您可以使用 remapCoordinateSystem() 方法,將螢幕方向值轉譯為 參照。

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private val accelerometerReading = FloatArray(3)
    private val magnetometerReading = FloatArray(3)

    private val rotationMatrix = FloatArray(9)
    private val orientationAngles = FloatArray(3)

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    override fun onResume() {
        super.onResume()

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also { accelerometer ->
            sensorManager.registerListener(
                    this,
                    accelerometer,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
        sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also { magneticField ->
            sensorManager.registerListener(
                    this,
                    magneticField,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
    }

    override fun onPause() {
        super.onPause()

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this)
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    override fun onSensorChanged(event: SensorEvent) {
        if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
            System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
        } else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    fun updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(
                rotationMatrix,
                null,
                accelerometerReading,
                magnetometerReading
        )

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles)

        // "orientationAngles" now has up-to-date information.
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {

    private SensorManager sensorManager;
    private final float[] accelerometerReading = new float[3];
    private final float[] magnetometerReading = new float[3];

    private final float[] rotationMatrix = new float[9];
    private final float[] orientationAngles = new float[3];

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (accelerometer != null) {
            sensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
        Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (magneticField != null) {
            sensorManager.registerListener(this, magneticField,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this);
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
          System.arraycopy(event.values, 0, accelerometerReading,
              0, accelerometerReading.length);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading,
                0, magnetometerReading.length);
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    public void updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(rotationMatrix, null,
            accelerometerReading, magnetometerReading);

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles);

        // "orientationAngles" now has up-to-date information.
    }
}

通常並不需要執行任何資料處理或篩選 裝置的原始方向角度,而不是翻譯感應器的 用於應用程式參照架構的座標系統。

使用地磁場感應器

您可以利用地磁場感應器,監測地球磁場的變化。 以下程式碼顯示如何取得預設地磁場感應器的例項:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

注意: 如果應用程式指定 Android 12 (API 級別 31) 或 也就是 頻率限制

這種感應器可以為三個座標軸分別提供原始現場強度資料 (以 μT 為單位)。 在一般情況下,你不必直接使用這個感應器。您可以改用旋轉向量 感應器,判斷原始旋轉動作,也可以使用加速計和地磁場 感應器搭配 getRotationMatrix() 方法,即可取得旋轉矩陣和對齊矩陣。接著 使用這些矩陣搭配 getOrientation()getInclination() 方法來取得方位詞 以及地磁感應資料的

注意: 測試應用程式時,可改善的空間 以 8 字形揮動裝置,展現感應器的準確度。

使用未校正的磁力儀

未校正的磁力儀與測地磁場相似 感應器,但磁場不會套用硬鐵校正功能。工廠校正 和溫度補償機制仍會套用至磁場。未校正的磁力儀 有助於處理不良的硬鐵估計值。一般而言,geomagneticsensor_event.values[0] 會接近 uncalibrated_magnetometer_event.values[0] - uncalibrated_magnetometer_event.values[3]。也就是說

calibrated_x ~= uncalibrated_x - bias_estimate_x

注意:未經校正的感應器會提供更多原始結果,且可能會 其中所含的偏誤,但他們的測量結果在經過修正後,跳躍次數較少 校正。有些應用程式可能偏好這些未校正的結果,讓結果更順暢 可靠又可靠的方式舉例來說,如果應用程式嘗試自行進行感應器融合 導入色調實際上可能會扭曲結果。

除了磁場外,未校正的磁力儀也提供 估計每個軸的硬鐵偏誤以下程式碼顯示如何取得 未校正的預設磁力儀:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);

使用鄰近感應器

鄰近感應器會判斷物體與裝置之間的距離。下列 程式碼顯示如何取得預設鄰近感應器的執行個體:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

鄰近感應器通常用於判斷人頭與臉部之間的距離 的手機裝置上 (例如撥打或接聽電話時)。大多數 鄰近感應器會傳回絕對距離 (公分),但部分感應器只會在 。

注意:在某些裝置型號上,鄰近感應器位於 如果在螢幕關閉時啟用該模式,畫面上可能會顯示閃爍的圓點 保持開啟。

以下程式碼說明如何使用鄰近感應器:

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private var proximity: Sensor? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        val distance = event.values[0]
        // Do something with this sensor data.
    }

    override fun onResume() {
        // Register a listener for the sensor.
        super.onResume()

        proximity?.also { proximity ->
            sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor proximity;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        float distance = event.values[0];
        // Do something with this sensor data.
    }

    @Override
    protected void onResume() {
        // Register a listener for the sensor.
        super.onResume();
        sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL);
      }

    @Override
    protected void onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

注意:部分鄰近感應器會傳回代表 「附近」或「最遠」在這種情況下,感應器通常會回報最遠狀態的最大範圍值 而接近狀態時的值也較小一般而言,最遠值是 >5 公分,但實際時間可能會有所差異 包括感應器和感應器您可以使用 getMaximumRange() 方法判斷感應器的最大範圍。

另請參閱