Cảm biến vị trí

Nền tảng Android cung cấp 2 cảm biến giúp bạn xác định vị trí của thiết bị: cảm biến địa từ trường và gia tốc kế. Nền tảng Android cũng cung cấp một cảm biến cho phép bạn xác định khoảng cách giữa khuôn mặt của thiết bị với một đối tượng (được gọi là cảm biến khoảng cách gần). Cảm biến địa từ trường và cảm biến độ gần dựa trên phần cứng. Hầu hết các nhà sản xuất điện thoại di động và máy tính bảng đều có cảm biến địa từ trường. Tương tự như vậy, các nhà sản xuất điện thoại di động thường tích hợp cảm biến độ gần để xác định thời điểm điện thoại di động được đưa lại gần khuôn mặt người dùng (ví dụ: trong khi gọi điện thoại). Để xác định hướng của thiết bị, bạn có thể sử dụng kết quả đọc từ gia tốc kế và cảm biến địa từ trường của thiết bị.

Lưu ý: Cảm biến hướng đã ngừng hoạt động trong Android 2.2 (API cấp 8) và loại cảm biến hướng đã ngừng hoạt động trong Android 4.4W (API cấp 20).

Cảm biến vị trí rất hữu ích trong việc xác định vị trí thực tế của một thiết bị trong hệ quy chiếu của thế giới. Ví dụ: bạn có thể sử dụng cảm biến địa từ trường kết hợp với gia tốc kế để xác định vị trí của một thiết bị so với cực từ phía bắc. Bạn cũng có thể dùng các cảm biến này để xác định hướng của thiết bị trong khung tham chiếu của ứng dụng. Cảm biến vị trí thường không dùng để theo dõi chuyển động hoặc chuyển động của thiết bị, chẳng hạn như rung, nghiêng hoặc đẩy (để biết thêm thông tin, hãy xem bài viết Cảm biến chuyển động).

Cảm biến trường địa từ và gia tốc kế trả về các mảng đa chiều gồm các giá trị cảm biến cho mỗi SensorEvent. Ví dụ: cảm biến trường địa từ cung cấp các giá trị cường độ trường địa từ cho từng trục toạ độ trong một sự kiện cảm biến. Tương tự như vậy, cảm biến gia tốc kế đo lường gia tốc áp dụng cho thiết bị trong một sự kiện cảm biến. Để biết thêm thông tin về hệ toạ độ mà cảm biến sử dụng, hãy xem bài viết Hệ toạ độ cảm biến. Cảm biến độ gần cung cấp một giá trị duy nhất cho mỗi sự kiện cảm biến. Bảng 1 tóm tắt các cảm biến vị trí được hỗ trợ trên nền tảng Android.

Bảng 1. Cảm biến vị trí được hỗ trợ trên nền tảng Android.

Cảm biến Dữ liệu sự kiện cảm biến Nội dung mô tả Đơn vị đo
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] Thành phần vectơ xoay dọc theo trục x (x * sin(=/2)). Không có đơn vị
SensorEvent.values[1] Thành phần vectơ xoay dọc theo trục y (y * sin(=/2)).
SensorEvent.values[2] Thành phần vectơ xoay dọc theo trục z (z * sin(=/2)).
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] Thành phần vectơ xoay dọc theo trục x (x * sin(=/2)). Không có đơn vị
SensorEvent.values[1] Thành phần vectơ xoay dọc theo trục y (y * sin(=/2)).
SensorEvent.values[2] Thành phần vectơ xoay dọc theo trục z (z * sin(=/2)).
TYPE_MAGNETIC_FIELD SensorEvent.values[0] Cường độ trường địa từ dọc theo trục x. μT
SensorEvent.values[1] Cường độ trường địa từ dọc trục y.
SensorEvent.values[2] Cường độ trường địa từ dọc theo trục z.
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] Cường độ trường địa từ (không có hiệu chuẩn sắt cứng) dọc theo trục x. μT
SensorEvent.values[1] Cường độ trường địa từ (không có hiệu chuẩn sắt cứng) dọc theo trục y.
SensorEvent.values[2] Cường độ trường địa từ (không có hiệu chuẩn sắt cứng) dọc theo trục z.
SensorEvent.values[3] Ước tính độ lệch sắt dọc theo trục x.
SensorEvent.values[4] Ước tính độ lệch sắt dọc theo trục y.
SensorEvent.values[5] Ước tính độ lệch sắt dọc theo trục z.
TYPE_ORIENTATION1 SensorEvent.values[0] Góc phương vị (góc xung quanh trục z). Độ
SensorEvent.values[1] Cao độ (góc xung quanh trục x).
SensorEvent.values[2] Cuộn (góc xung quanh trục y).
TYPE_PROXIMITY SensorEvent.values[0] Khoảng cách từ đối tượng.2 cm

1Cảm biến này đã ngừng hoạt động trong Android 2.2 (API cấp 8) và loại cảm biến này cũng không còn được dùng trong Android 4.4W (API cấp 20). Khung cảm biến cung cấp các phương thức thay thế để lấy hướng thiết bị. Điều này được thảo luận trong bài viết Tính toán hướng của thiết bị.

2 Một số cảm biến độ gần chỉ cung cấp các giá trị nhị phân đại diện cho khoảng cách gần và xa.

Sử dụng cảm biến vectơ xoay của trò chơi

Cảm biến vectơ xoay trò chơi giống với Cảm biến vectơ xoay, ngoại trừ không dùng trường địa từ. Do đó, trục Y không trỏ về phía bắc mà thay vào đó là một số tham chiếu khác. Tham chiếu đó được phép trôi theo cùng thứ tự cường độ khi con quay hồi chuyển di chuyển quanh trục Z.

Vì cảm biến vectơ xoay trò chơi không sử dụng từ trường, nên phép xoay tương đối sẽ chính xác hơn và không bị ảnh hưởng bởi các thay đổi từ trường. Sử dụng cảm biến này trong trò chơi nếu bạn không quan tâm đến vị trí của hướng bắc và vectơ xoay thông thường không phù hợp với nhu cầu của bạn vì vectơ này phụ thuộc vào từ trường.

Mã sau đây cho bạn biết cách lấy một thực thể của cảm biến vectơ xoay trò chơi mặc định:

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);

Sử dụng cảm biến vectơ xoay địa từ

Cảm biến vectơ xoay địa từ tương tự như cảm biến vectơ xoay, nhưng không sử dụng con quay hồi chuyển. Độ chính xác của cảm biến này thấp hơn cảm biến vectơ xoay thông thường, nhưng mức tiêu thụ điện năng lại giảm. Chỉ sử dụng cảm biến này nếu bạn muốn thu thập thông tin về chế độ xoay ở chế độ nền mà không cần sử dụng quá nhiều pin. Cảm biến này hữu ích nhất khi được dùng cùng với việc tạo lô.

Mã sau đây cho bạn biết cách nhận thực thể của cảm biến vectơ xoay địa từ mặc định:

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);

Tính toán hướng của thiết bị

Bằng cách tính toán hướng của thiết bị, bạn có thể theo dõi vị trí của thiết bị so với khung tham chiếu của trái đất (cụ thể là cực từ phía bắc). Mã sau đây cho bạn biết cách tính toán hướng của thiết bị:

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);

Hệ thống tính toán các góc hướng bằng cách sử dụng cảm biến trường địa từ của thiết bị kết hợp với gia tốc kế trên thiết bị. Khi sử dụng 2 cảm biến phần cứng này, hệ thống sẽ cung cấp dữ liệu cho 3 góc hướng sau:

  • Góc phương vị (độ xoay đối với trục -z). Đây là góc giữa hướng la bàn hiện tại của thiết bị và từ tính hướng bắc. Nếu cạnh trên của thiết bị hướng về phía bắc, thì góc phương vị là 0 độ; nếu cạnh trên hướng về phía nam, thì góc phương vị là 180 độ. Tương tự, nếu cạnh trên hướng về phía đông, thì góc phương vị là 90 độ và nếu cạnh trên hướng về phía Tây, thì góc phương vị là 270 độ.
  • Góc nghiêng (độ xoay đối với trục x). Đây là góc giữa một mặt phẳng song song với màn hình của thiết bị và một mặt phẳng song song với mặt đất. Nếu bạn giữ thiết bị song song với mặt đất sao cho cạnh dưới gần nhất với bạn và nghiêng cạnh trên của thiết bị về phía mặt đất, thì góc nghiêng sẽ trở thành giá trị dương. Nghiêng theo hướng ngược lại (di chuyển cạnh trên của thiết bị ra xa mặt đất) sẽ khiến góc nghiêng trở thành giá trị âm. Phạm vi giá trị là từ -90 độ đến 90 độ.
  • Roll (độ xoay đối với trục y). Đây là góc giữa một mặt phẳng vuông góc với màn hình của thiết bị và một mặt phẳng vuông góc với mặt đất. Nếu bạn giữ thiết bị song song với mặt đất với cạnh dưới gần nhất và nghiêng cạnh trái của thiết bị về phía mặt đất, thì góc cuộn sẽ trở thành giá trị dương. Việc nghiêng theo hướng ngược lại (di chuyển cạnh phải của thiết bị về phía mặt đất) sẽ khiến góc cuộn trở thành giá trị âm. Phạm vi giá trị là từ -180 độ đến 180 độ.

Lưu ý: Định nghĩa cuộn của cảm biến đã thay đổi để phản ánh phần lớn quy trình triển khai trong hệ sinh thái cảm biến địa lý.

Lưu ý rằng các góc này hoạt động thuộc một hệ toạ độ khác với hệ toạ độ dùng trong ngành hàng không (cho các góc yaw, các cao độ và một trục tung). Trong hệ thống hàng không, trục x nằm dọc theo cạnh dài của máy bay, từ đuôi đến mũi.

Cảm biến hướng lấy dữ liệu bằng cách xử lý dữ liệu cảm biến thô từ gia tốc kế và cảm biến trường địa từ. Do phải xử lý nhiều công việc, nên độ chính xác và độ chính xác của cảm biến hướng sẽ bị giảm. Cụ thể, cảm biến này chỉ đáng tin cậy khi góc cuộn bằng 0. Do đó, cảm biến hướng đã ngừng hoạt động trong Android 2.2 (API cấp 8) và loại cảm biến hướng đã ngừng hoạt động trong Android 4.4W (API cấp 20). Thay vì sử dụng dữ liệu thô từ cảm biến hướng, bạn nên sử dụng phương thức getRotationMatrix() kết hợp với phương thức getOrientation() để tính toán các giá trị hướng, như trong mã mẫu sau. Trong quá trình này, bạn có thể sử dụng phương thức remapCoordinateSystem() để chuyển đổi các giá trị hướng sang khung tham chiếu của ứng dụng.

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.
    }
}

Thường thì bạn không cần phải xử lý dữ liệu hoặc lọc các góc hướng thô của thiết bị ngoài việc dịch hệ toạ độ của cảm biến sang khung tham chiếu của ứng dụng.

Sử dụng cảm biến địa từ trường

Cảm biến trường địa từ cho phép bạn theo dõi những thay đổi trong từ trường của trái đất. Mã sau đây cho bạn biết cách tải một thực thể của cảm biến địa từ trường mặc định:

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);

Lưu ý: Nếu ứng dụng của bạn nhắm đến Android 12 (API cấp 31) trở lên, thì cảm biến này sẽ bị giới hạn số lượng.

Cảm biến này cung cấp dữ liệu cường độ trường thô (tính bằng μT) cho từng trục toạ độ. Thường thì bạn không cần phải sử dụng trực tiếp cảm biến này. Thay vào đó, bạn có thể sử dụng cảm biến vectơ xoay để xác định chuyển động xoay thô hoặc sử dụng cảm biến gia tốc kế và cảm biến địa từ cùng với phương thức getRotationMatrix() để lấy ma trận xoay và ma trận độ nghiêng. Sau đó, bạn có thể sử dụng các ma trận này bằng các phương thức getOrientation()getInclination() để thu thập dữ liệu về góc phương vị và độ nghiêng địa từ.

Lưu ý: Khi kiểm thử ứng dụng, bạn có thể cải thiện độ chính xác của cảm biến bằng cách vẫy thiết bị theo hình hình 8.

Sử dụng từ kế chưa hiệu chỉnh

Từ kế chưa được hiệu chỉnh sẽ tương tự như cảm biến từ trường địa từ, ngoại trừ việc không hiệu chuẩn kim loại cứng được áp dụng cho từ trường. Hiệu chuẩn nhà máy và bù nhiệt độ vẫn được áp dụng cho từ trường. Từ kế chưa hiệu chỉnh rất hữu ích khi xử lý các phép ước tính sắt cứng không chính xác. Nhìn chung, geomagneticsensor_event.values[0] sẽ gần với uncalibrated_magnetometer_event.values[0] - uncalibrated_magnetometer_event.values[3]. Tức là,

calibrated_x ~= uncalibrated_x - bias_estimate_x

Lưu ý: Cảm biến chưa hiệu chỉnh cung cấp kết quả thô hơn và có thể có một vài sai lệch, nhưng số đo của cảm biến có ít bước nhảy hơn từ các hiệu chỉnh được áp dụng thông qua quá trình hiệu chuẩn. Một số ứng dụng có thể muốn kết quả chưa được hiệu chỉnh như vậy mượt mà và đáng tin cậy hơn. Ví dụ: nếu một ứng dụng đang cố gắng tiến hành quá trình hợp nhất cảm biến của riêng mình, thì việc cung cấp tính năng hiệu chuẩn thực sự có thể làm sai lệch kết quả.

Ngoài từ trường, từ kế chưa hiệu chỉnh cũng cung cấp độ chệch sắt cứng ước tính ở mỗi trục. Mã sau đây cho bạn biết cách lấy một thực thể của từ kế mặc định chưa hiệu chỉnh:

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);

Dùng cảm biến độ gần

Cảm biến độ gần cho phép bạn xác định khoảng cách từ một đối tượng đến một thiết bị. Mã sau đây cho bạn biết cách tải thực thể của cảm biến độ gần mặc định:

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);

Cảm biến độ gần thường được dùng để xác định khoảng cách từ đầu của một người đến khuôn mặt của thiết bị điện thoại di động (ví dụ: khi người dùng đang thực hiện hoặc nhận cuộc gọi điện thoại). Hầu hết các cảm biến khoảng cách gần đều trả về khoảng cách tuyệt đối (tính bằng cm), nhưng một số cảm biến chỉ trả về giá trị gần và xa.

Lưu ý: Trên một số kiểu thiết bị, cảm biến độ gần nằm ở bên dưới màn hình. Điều này có thể khiến dấu chấm nhấp nháy xuất hiện trên màn hình nếu bạn bật khi màn hình đang bật.

Mã sau đây cho bạn biết cách sử dụng cảm biến độ gần:

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);
    }
}

Lưu ý: Một số cảm biến độ gần trả về các giá trị nhị phân biểu thị "gần" hoặc "xa". Trong trường hợp này, cảm biến thường báo cáo giá trị phạm vi tối đa ở trạng thái xa và giá trị nhỏ hơn ở trạng thái gần. Thông thường, giá trị xa là một giá trị > 5 cm, nhưng giá trị này có thể khác nhau giữa các cảm biến. Bạn có thể xác định phạm vi tối đa của cảm biến bằng cách sử dụng phương thức getMaximumRange().

Bạn cũng nên đọc