חיישני מיקום

בפלטפורמת Android יש שני חיישנים שמאפשרים לקבוע את המיקום של המכשיר: חיישן השדה הגאומגנטי ומד התאוצה. מכשיר Android מספקת גם חיישן שמאפשר לך לקבוע את מידת המרחק בין הפנים מכשיר צמוד לאובייקט (שנקרא חיישן קירבה). חיישן שדה גיאומגנטי וחיישן הקירבה מבוססים על חומרה. רוב יצרני הטלפונים והטאבלטים כוללים חיישן של שדה מגנטי גיאוגרפי. באופן דומה, בדרך כלל יצרני מכשירי כף היד כוללים חיישן קירבה כדי לקבוע מתי מכשיר כף היד מוחזק קרוב לפנים של המשתמש (לדוגמה, במהלך שיחת טלפון). כדי לקבוע את הכיוון של המכשיר, אפשר להשתמש בקריאות של מד התאוצה ושל חיישן השדה הגיאומגנטי במכשיר.

הערה: חיישן הכיוון הוצא משימוש ב-Android 2.2 (API ברמה 8), וסוג חיישן הכיוון הוצא משימוש ב-Android 4.4W (רמת API 20).

חיישני המיקום שימושיים לקביעת המיקום הפיזי של המכשיר את מודל השיוך של העולם. לדוגמה, אפשר להשתמש בשדה הגאומגנטי החיישן בשילוב עם מד התאוצה כדי לקבוע את מיקום המכשיר ביחס לקוטב הצפוני המגנטי. אפשר להשתמש בחיישנים האלה גם כדי לקבוע את כיוון המכשיר במסגרת ההפניה של האפליקציה. בדרך כלל לא משתמשים בחיישנים למיקום כדי לעקוב אחרי תנועה או תנודות של המכשיר, כמו רעידות, הטיות או דחיפה (מידע נוסף זמין במאמר חיישני תנועה).

חיישן השדה הגאומגנטי ומד התאוצה מחזירים מערכים רב-ממדיים מערכי החיישנים של כל SensorEvent. לדוגמה, חיישן השדה הגיאומגנטי מספק ערכים של עוצמת השדה הגיאומגנטי לכל אחד משלושת צירי הקואורדינטות במהלך אירוע חיישן יחיד. באופן דומה, חיישן מד התאוצה מודד את התאוצה שחלה על המכשיר במהלך אירוע חיישן. מידע נוסף על מערכות קואורדינטות שבהן חיישנים משתמשים זמין במאמר מערכות קואורדינטות של חיישנים. חיישן הקרבה מספק ערך יחיד לכל אירוע חיישן. טבלה 1 מסכמת את חיישני המיקום נתמך בפלטפורמת Android.

טבלה 1. חיישני מיקום הנתמכים בפלטפורמת Android.

חיישן נתוני אירועים מחיישנים תיאור יחידות מידה
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] רכיב וקטור סיבוב לאורך ציר ה-x (x * sin(סיכום/2)). ללא יחידה
SensorEvent.values[1] רכיב וקטור הסיבוב לאורך ציר ה-y (y * sin(θ/2)).
SensorEvent.values[2] רכיב וקטור סיבוב לאורך ציר ה-z (z * sin(ישתמשו במחשב 2)).
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] רכיב וקטור הסיבוב לאורך ציר ה-x (x * sin(θ/2)). ללא יחידה
SensorEvent.values[1] רכיב וקטור הסיבוב לאורך ציר ה-y (y * sin(θ/2)).
SensorEvent.values[2] רכיב וקטור הסיבוב לאורך ציר z‏ (z * sin(θ/2)).
TYPE_MAGNETIC_FIELD SensorEvent.values[0] עוצמת השדה הגיאומגנטי לאורך ציר ה-X. μT
SensorEvent.values[1] עוצמת שדה גיאומגנטי לאורך ציר ה-Y.
SensorEvent.values[2] עוצמת שדה גיאומגנטי לאורך ציר ה-z.
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] עוצמת שדה גיאומגנטי (ללא כיול ברזל קשיח) לאורך ציר ה-X. μT
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). מסגרת החיישן מספקת שיטות חלופיות לצירוף המכשיר לכיוון אוטומטי, שנדון ב בכיוון של המכשיר.

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

המערכת מחשבת את זוויות הכיוון באמצעות התנועה הגאומגנטית של המכשיר חיישן שדה בשילוב עם מד התאוצה של המכשיר. באמצעות שני חיישני החומרה האלה, המערכת מספקת נתונים לגבי שלושת זוויות הכיוון הבאות:

  • Azimuth (מעלות סיבוב סביב ציר z-). זהו הזווית בין כיוון המצפן הנוכחי של המכשיר לבין צפון מגנטי. אם הקצה העליון של המכשיר פונה לכיוון צפון מגנטי, האזימוט הוא 0 מעלות; אם הקצה העליון פונה דרומה, האזימוט הוא 180 מעלות. באופן דומה, אם הקצה העליון פונה מזרחה, האזימוט הוא 90 מעלות, ואם הקצה העליון שפונה מערבה, האזימוט הוא 270 מעלות.
  • נטייה (מעלות של סיבוב סביב ציר ה-x). כאן בין מישור מקביל למסך המכשיר לבין מישור מקביל לקרקע. אם מחזיקים את המכשיר במקביל לאדמה, כך שהקצה התחתון קרוב אליכם, ומטים את הקצה העליון של המכשיר לכיוון האדמה, זווית ההטיה תהפוך לחיובית. הטיה בכיוון ההפוך – כלומר, הזזת הקצה העליון של המכשיר הרחק מהאדמה – גורמת לזווית השיפוע להיות שלילית. טווח הערכים הוא -90 מעלות עד 90 מעלות.
  • גליל (מעלות הסיבוב סביב ציר ה-Y) כאן הזווית בין מישור מאונך למסך המכשיר לבין מישור מאונך לקרקע. אם מחזיקים את המכשיר במקביל לקרקע כשהקצה התחתון קרוב אליך ביותר, והקצה השמאלי של המכשיר לכיוון הקרקע, זווית הגלגול הופכת לחיובית. אם מטים את המכשיר בכיוון ההפוך – כלומר, מזיזים את הקצה הימני של המכשיר לכיוון הקרקע – זווית הנטייה תהפוך לשלילית. טווח הערכים הוא מ-180 מעלות ל-180 מעלות.

הערה: הגדרת הגליל של החיישן השתנתה כדי לשקף את הרוב המכריע של יישומים בסביבה העסקית של החיישן הגיאוגרפי (geosensor).

שימו לב שזוויות אלה פועלות ממערכת קואורדינטות שונה מזו אחד שמשמש לתעופה (לפיתון, לגובה ולגלגול). במערכת התעופה, ציר ה-x נמצא לאורך הצד הארוך של המישור, מהזנב עד האף.

חיישן הכיוון מסיק את הנתונים שלו על ידי עיבוד נתוני החיישן הגולמיים מהתאוצה ומחיישן השדה הגיאומגנטי. בגלל העומס הכבד את העיבוד המדובר, את הדיוק והדיוק של הכיוון החיישן מצטמצם. באופן ספציפי, החיישן הזה אמין רק הזווית היא 0. כתוצאה מכך, חיישן הכיוון הוצא משימוש ב-Android 2.2 (רמת API 8), וסוג חיישן הכיוון הוצא משימוש ב-Android 4.4W (רמת API 20). במקום להשתמש בנתונים גולמיים מחיישן הכיוון, מומלץ להשתמש ב-method‏ getRotationMatrix() בשילוב עם method‏ getOrientation() כדי לחשב את ערכי הכיוון, כפי שמתואר בדוגמת הקוד הבאה. כחלק מהתהליך הזה, אפשר להשתמש ב-method‏ 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() כדי לקבוע את הטווח המקסימלי של חיישן.

כדאי גם לקרוא את המאמרים הבאים: