센서 개요

대부분의 Android 지원 기기에는 움직임, 방향, 다양한 환경 조건을 측정하는 센서가 내장되어 있습니다. 이러한 센서는 높은 정밀도와 정확도로 원시 데이터를 제공하며 3차원 기기 움직임 또는 위치 지정을 모니터링하거나 기기 근처 주변 환경의 변화를 모니터링하려는 경우에 유용합니다. 예를 들어 게임에서 기기의 중력 센서로부터 읽은 값을 추적하여 기울이기, 흔들기, 회전, 스윙과 같은 복잡한 사용자 동작과 모션을 추론할 수 있습니다. 마찬가지로 날씨 애플리케이션에서 기기의 온도 센서와 습도 센서를 사용하여 이슬점을 계산하고 보고하거나 여행 애플리케이션에서 지자기장 센서와 가속도계를 사용하여 나침반 방위를 보고할 수 있습니다.

Android 플랫폼은 크게 세 가지 카테고리의 센서를 지원합니다.

  • 움직임 감지 센서

    이 센서는 세 축을 따라 가속력과 회전력을 측정합니다. 이 카테고리에는 가속도계, 중력 센서, 자이로스코프, 회전 벡터 센서가 포함됩니다.

  • 환경 센서

    이 센서는 주변 기온 및 압력, 조도, 습도와 같은 다양한 환경 매개변수를 측정합니다. 이 카테고리에는 기압계, 광도계, 온도계가 포함됩니다.

  • 위치 센서

    이 센서는 기기의 물리적 위치를 측정합니다. 이 카테고리에는 방향 센서와 자기계가 포함됩니다.

Android 센서 프레임워크를 사용하여 기기에서 사용 가능한 센서에 액세스하고 원시 센서 데이터를 획득할 수 있습니다. 센서 프레임워크는 다양한 센서 관련 작업을 실행하는 데 도움이 되는 여러 클래스와 인터페이스를 제공합니다. 예를 들어 센서 프레임워크를 사용하여 다음과 같은 작업을 실행할 수 있습니다.

  • 기기에서 사용할 수 있는 센서 확인
  • 최대 범위, 제조업체, 전원 요구사항, 해상도 등 개별 센서의 기능 확인
  • 원시 센서 데이터 획득 및 센서 데이터를 획득하는 최저 속도 정의
  • 센서 변경사항을 모니터링하는 센서 이벤트 리스너를 등록 및 등록 취소

이 주제에서는 Android 플랫폼에서 사용할 수 있는 센서의 개요를 제공합니다. 또한 센서 프레임워크도 소개합니다.

센서 소개

Android 센서 프레임워크를 사용하면 다양한 유형의 센서에 액세스할 수 있습니다. 이러한 센서 중 일부는 하드웨어 기반이고 일부는 소프트웨어 기반입니다. 하드웨어 기반 센서는 휴대전화 또는 태블릿 기기에 내장된 물리적 구성요소로, 가속도, 지자기장, 각도 변화와 같은 특정 환경 특성을 직접 측정하여 데이터를 얻습니다. 소프트웨어 기반 센서는 하드웨어 기반 센서를 모방하지만 물리적 기기가 아닙니다. 소프트웨어 기반 센서는 하나 이상의 하드웨어 기반 센서에서 데이터를 가져오며 가상 센서 또는 합성 센서라고도 합니다. 선형 가속 센서와 중력 센서는 소프트웨어 기반 센서의 예입니다. 표 1에는 Android 플랫폼에서 지원하는 센서가 요약되어 있습니다.

모든 유형의 센서를 갖춘 Android 지원 기기는 거의 없습니다. 예를 들어 대부분의 휴대전화 기기와 태블릿에는 가속도계와 자기계가 있지만 기압계나 온도계가 있는 기기는 더 적습니다. 또한 한 기기에 동일 유형의 센서가 두 개 이상 있을 수 있습니다. 예를 들어 한 기기에 범위가 서로 다른 중력 센서가 두 개 있을 수 있습니다.

표 1. Android 플랫폼에서 지원하는 센서 유형

센서 유형 설명 일반적인 용도
TYPE_ACCELEROMETER 하드웨어 중력을 포함하여 세 개의 모든 물리적 축 (x, y, z)에서 기기에 적용되는 가속력을 m/s2 단위로 측정합니다. 움직임 감지 (흔들기, 기울이기 등).
TYPE_AMBIENT_TEMPERATURE 하드웨어 주변 상온을 섭씨(°C) 단위로 측정합니다. 아래 내용을 참조하세요. 기온 모니터링.
TYPE_GRAVITY 소프트웨어 또는 하드웨어 세 개의 모든 물리적 축 (x, y, z)에서 기기에 적용되는 중력을 m/s2 단위로 측정합니다. 움직임 감지 (흔들기, 기울이기 등).
TYPE_GYROSCOPE 하드웨어 각 물리적 축(x, y, z) 둘레의 기기 회전 속도를 rad/s 단위로 측정합니다. 회전 감지(회전, 돌리기 등).
TYPE_LIGHT 하드웨어 주변 조도를 lx 단위로 측정합니다. 화면 밝기 제어.
TYPE_LINEAR_ACCELERATION 소프트웨어 또는 하드웨어 중력을 제외하고 세 개의 모든 물리적 축 (x, y, z)에서 기기에 적용되는 가속력을 m/s2 단위로 측정합니다. 단일 축을 따라 가속도 모니터링.
TYPE_MAGNETIC_FIELD 하드웨어 세 개의 모든 물리적 축 (x, y, z) 주변의 지자기장을 μT 단위로 측정합니다. 나침반 만들기.
TYPE_ORIENTATION 소프트웨어 세 개의 모든 물리적 축(x, y, z) 둘레의 기기 회전 각도를 측정합니다. API 수준 3부터 중력 센서와 지자기장 센서를 getRotationMatrix() 메서드와 함께 사용하여 기기의 경사 행렬과 회전 행렬을 얻을 수 있습니다. 기기 위치 확인.
TYPE_PRESSURE 하드웨어 주변 기압을 hPa 또는 mbar 단위로 측정합니다. 기압 변화 모니터링.
TYPE_PROXIMITY 하드웨어 기기의 뷰 화면을 기준으로 객체의 근접도를 cm 단위로 측정합니다. 이 센서는 일반적으로 휴대전화를 귀에 대고 있는지 확인하는 데 사용됩니다. 통화 중 전화 위치.
TYPE_RELATIVE_HUMIDITY 하드웨어 상대 주변 습도를 퍼센트(%) 단위로 측정합니다. 이슬점, 절대 및 상대 습도 모니터링.
TYPE_ROTATION_VECTOR 소프트웨어 또는 하드웨어 기기 회전 벡터의 세 가지 요소를 제공하여 기기의 방향을 측정합니다. 움직임 감지 및 회전 감지.
TYPE_TEMPERATURE 하드웨어 기기의 온도를 섭씨(°C) 단위로 측정합니다. 이 센서는 기기마다 다르게 구현되며 API 레벨 14에서 TYPE_AMBIENT_TEMPERATURE 센서로 대체되었습니다. 온도 모니터링.

센서 프레임워크

Android 센서 프레임워크를 사용하여 이러한 센서에 액세스하고 원시 센서 데이터를 획득할 수 있습니다. 센서 프레임워크는 android.hardware 패키지의 일부이며 다음과 같은 클래스 및 인터페이스를 포함합니다.

SensorManager
이 클래스를 사용하여 센서 서비스의 인스턴스를 만들 수 있습니다. 이 클래스는 센서 액세스 및 나열, 센서 이벤트 리스너 등록 및 등록 취소, 방향 정보 획득을 위한 다양한 방법을 제공합니다. 또한 센서 정확도를 보고하고 데이터 획득 속도를 설정하고 센서를 보정하는 데 사용되는 여러 센서 상수를 제공합니다.
Sensor
이 클래스를 사용하여 특정 센서의 인스턴스를 만들 수 있습니다. 이 클래스는 센서의 기능을 확인할 수 있는 다양한 메서드를 제공합니다.
SensorEvent
시스템에서는 이 클래스를 사용하여 센서 이벤트의 정보를 제공하는 센서 이벤트 객체를 만듭니다. 센서 이벤트 객체에는 원시 센서 데이터, 이벤트를 생성한 센서 유형, 데이터의 정확도, 이벤트의 타임스탬프와 같은 정보가 포함됩니다.
SensorEventListener
이 인터페이스를 사용하여 센서 값이 변경되거나 센서 정확도가 변경될 때 알림 (센서 이벤트)을 수신하는 콜백 메서드를 두 개 만들 수 있습니다.

일반적인 애플리케이션에서는 이러한 센서 관련 API를 사용하여 두 가지 기본 작업을 실행합니다.

  • 센서 및 센서 기능 식별

    런타임에 센서 및 센서 기능을 식별하는 기능은 애플리케이션에 특정 센서 유형이나 기능에 의존하는 기능이 있는 경우 유용합니다. 예를 들어 기기에 존재하는 모든 센서를 식별하고 존재하지 않는 센서에 의존하는 모든 애플리케이션 기능을 사용 중지할 수 있습니다. 마찬가지로 특정 유형의 센서를 모두 식별하여 최적의 애플리케이션 성능을 제공하는 센서 구현을 선택할 수도 있습니다.

  • 센서 이벤트 모니터링

    센서 이벤트 모니터링을 통해 원시 센서 데이터를 획득할 수 있습니다. 센서 이벤트는 센서가 측정 중인 매개변수의 변화를 감지할 때마다 발생합니다. 센서 이벤트는 이벤트를 트리거한 센서의 이름, 이벤트의 타임스탬프, 이벤트의 정확도, 이벤트를 트리거한 원시 센서 데이터 등 네 가지 정보를 제공합니다.

센서 사용 가능 여부

센서 사용 가능 여부는 기기에 따라 다를 수 있으며 Android 버전 간에도 다를 수 있습니다. 이는 Android 센서들이 도입되는 과정에서 여러 플랫폼이 출시되었기 때문입니다. 예를 들어 많은 센서가 Android 1.5 (API 수준 3)에서 도입되었지만 일부 센서는 Android 2.3 (API 수준 9)까지 구현되지 않았으며 사용할 수 없었습니다. 마찬가지로 여러 센서가 Android 2.3 (API 수준 9) 및 Android 4.0 (API 수준 14)에서 도입되었습니다. 두 개의 센서가 지원 중단되고 기능이 개선된 새로운 센서로 대체되었습니다.

표 2에는 플랫폼별 각 센서의 사용 가능 여부가 요약되어 있습니다. 센서 변경사항이 포함된 플랫폼이므로 4개 플랫폼만 나열되어 있습니다. 지원 중단된 것으로 나열된 센서는 Android의 향후 버전과의 호환성 정책에 따라 (기기에 센서가 존재하는 한) 이후 플랫폼에서 여전히 사용할 수 있습니다.

표 2. 플랫폼별 센서 사용 가능 여부

센서 Android 4.0
(API 레벨 14)
Android 2.3
(API 레벨 9)
Android 2.2
(API 레벨 8)
Android 1.5
(API 레벨 3)
TYPE_ACCELEROMETER
TYPE_AMBIENT_TEMPERATURE 해당 없음 해당 없음 해당 사항 없음
TYPE_GRAVITY 해당 없음 해당 사항 없음
TYPE_GYROSCOPE 해당 없음1 해당 없음1
TYPE_LIGHT
TYPE_LINEAR_ACCELERATION 해당 없음 해당 사항 없음
TYPE_MAGNETIC_FIELD
TYPE_ORIENTATION 2 2 2
TYPE_PRESSURE 해당 없음1 해당 없음1
TYPE_PROXIMITY
TYPE_RELATIVE_HUMIDITY 해당 없음 해당 없음 해당 사항 없음
TYPE_ROTATION_VECTOR 해당 없음 해당 사항 없음
TYPE_TEMPERATURE 2

1 이 센서 유형은 Android 1.5 (API 수준 3)에서 추가되었지만 Android 2.3 (API 수준 9)까지 사용할 수 없었습니다.

2 이 센서는 사용할 수 있지만 지원 중단되었습니다.

센서 및 센서 기능 식별

Android 센서 프레임워크는 런타임에 기기에 어떤 센서가 있는지 쉽게 확인할 수 있는 여러 가지 메서드를 제공합니다. API는 최대 범위, 해상도, 전원 요구사항과 같은 각 센서의 기능을 확인할 수 있는 메서드도 제공합니다.

기기에 있는 센서를 식별하려면 먼저 센서 서비스의 참조를 가져와야 합니다. 이렇게 하려면 getSystemService() 메서드를 호출하고 SENSOR_SERVICE 인수를 전달하여 SensorManager 클래스의 인스턴스를 만듭니다. 예를 들면 다음과 같습니다.

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

자바

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

그런 다음 getSensorList() 메서드를 호출하고 TYPE_ALL 상수를 사용하여 기기에 있는 모든 센서의 목록을 가져올 수 있습니다. 예를 들면 다음과 같습니다.

Kotlin

val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)

자바

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

특정 유형의 센서를 모두 나열하려는 경우 TYPE_ALL 대신 TYPE_GYROSCOPE, TYPE_LINEAR_ACCELERATION 또는 TYPE_GRAVITY와 같은 다른 상수를 사용할 수 있습니다.

getDefaultSensor() 메서드를 호출하고 특정 센서의 유형 상수를 전달하여 기기에 특정 유형의 센서가 있는지 여부도 확인할 수 있습니다. 기기에 동일 유형의 센서가 두 개 이상 있는 경우 센서 중 하나를 기본 센서로 지정해야 합니다. 동일 센서 유형에 기본 센서가 없는 경우 메서드를 호출하면 null이 반환되며 이는 기기에 해당 유형의 센서가 없다는 것을 의미합니다. 예를 들어 다음 코드는 기기에 자기계가 있는지 확인합니다.

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

자바

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

참고: Android에서는 기기 제조업체가 Android 지원 기기에 특정 유형의 센서를 내장할 필요가 없으므로 기기의 센서를 다양하게 구성할 수 있습니다.

기기에 있는 센서를 나열하는 것 외에 Sensor 클래스의 공개 메서드를 사용하여 개별 센서의 기능 및 속성을 확인할 수 있습니다. 이 기능은 애플리케이션이 기기에서 사용할 수 있는 센서 또는 센서 기능에 따라 다르게 작동하도록 하려는 경우에 유용합니다. 예를 들어 getResolution()getMaximumRange() 메서드를 사용하여 센서의 해상도 및 최대 측정 범위를 얻을 수 있습니다. getPower() 메서드를 사용하여 센서의 전원 요구사항을 가져올 수도 있습니다.

공개 메서드 중 두 개는 애플리케이션을 서로 다른 제조업체의 센서 또는 서로 다른 버전의 센서에 최적화하려는 경우에 특히 유용합니다. 예를 들어 애플리케이션에서 기울기 및 흔들기와 같은 사용자 동작을 모니터링해야 하는 경우 특정 공급업체의 중력 센서가 있는 최신 기기용 데이터 필터링 규칙 및 최적화 한 세트를 만들고 중력 센서가 없고 가속도계만 있는 기기용 데이터 필터링 규칙 및 최적화 한 세트를 만들 수 있습니다. 다음 코드 샘플은 getVendor()getVersion() 메서드를 사용하여 이 작업을 실행하는 방법을 보여줍니다. 이 샘플에서는 공급업체가 Google LLC이고 버전 번호가 3인 중력 센서를 찾습니다. 특정 센서가 기기에 존재하지 않는 경우 가속도계를 사용합니다.

Kotlin

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

...

sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
    val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)
    // Use the version 3 gravity sensor.
    mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 }
}
if (mSensor == null) {
    // Use the accelerometer.
    mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    } else {
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
        null
    }
}

자바

private SensorManager sensorManager;
private Sensor mSensor;

...

sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
    List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
    for(int i=0; i<gravSensors.size(); i++) {
        if ((gravSensors.get(i).getVendor().contains("Google LLC")) &&
           (gravSensors.get(i).getVersion() == 3)){
            // Use the version 3 gravity sensor.
            mSensor = gravSensors.get(i);
        }
    }
}
if (mSensor == null){
    // Use the accelerometer.
    if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
        mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    } else{
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
    }
}

또 다른 유용한 메서드는 센서가 데이터를 감지하는 데 사용할 수 있는 최소 시간 간격 (마이크로초)을 반환하는 getMinDelay() 메서드입니다. getMinDelay() 메서드에 0이 아닌 값을 반환하는 모든 센서는 스트리밍 센서입니다. 스트리밍 센서는 일정한 간격으로 데이터를 감지하며 Android 2.3 (API 수준 9)에서 도입되었습니다. getMinDelay() 메서드를 호출할 때 센서가 0을 반환하면 센서는 감지 중인 매개변수가 변경될 때만 데이터를 보고하므로 스트리밍 센서가 아니라는 의미입니다.

getMinDelay() 메서드는 센서가 데이터를 획득할 수 있는 최대 속도를 결정할 수 있으므로 유용합니다. 애플리케이션의 특정 기능에 높은 데이터 획득 속도 또는 스트리밍 센서가 필요한 경우 이 메서드를 사용하여 센서가 요구사항을 충족하는지 확인한 다음 애플리케이션의 관련 기능을 적절하게 사용 설정하거나 사용 중지할 수 있습니다.

주의: 센서의 최대 데이터 획득 속도가 반드시 센서 프레임워크가 센서 데이터를 애플리케이션에 전달하는 속도는 아닙니다. 센서 프레임워크는 센서 이벤트를 통해 데이터를 보고하며 여러 요인이 애플리케이션에서 센서 이벤트를 수신하는 속도에 영향을 미칩니다. 자세한 내용은 센서 이벤트 모니터링을 참조하세요.

센서 이벤트 모니터링

원시 센서 데이터를 모니터링하려면 SensorEventListener 인터페이스를 통해 노출되는 콜백 메서드 두 개(onAccuracyChanged()onSensorChanged())를 구현해야 합니다. Android 시스템에서는 다음과 같은 일이 발생할 때마다 이러한 메서드를 호출합니다.

다음 코드는 onSensorChanged() 메서드를 사용하여 광 센서의 데이터를 모니터링하는 방법을 보여줍니다. 이 예에서는 main.xml 파일에 정의된 TextView의 원시 센서 데이터를 sensor_data로 표시합니다.

Kotlin

class SensorActivity : Activity(), SensorEventListener {
    private lateinit var sensorManager: SensorManager
    private var mLight: Sensor? = null

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

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
    }

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

    override fun onSensorChanged(event: SensorEvent) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        val lux = event.values[0]
        // Do something with this sensor value.
    }

    override fun onResume() {
        super.onResume()
        mLight?.also { light ->
            sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

자바

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

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

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    }

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

    @Override
    public final void onSensorChanged(SensorEvent event) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        float lux = event.values[0];
        // Do something with this sensor value.
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

이 예에서는 registerListener() 메서드가 호출될 때 기본 데이터 지연(SENSOR_DELAY_NORMAL)이 지정됩니다. 데이터 지연 (또는 샘플링 레이트)은 센서 이벤트가 onSensorChanged() 콜백 메서드를 통해 애플리케이션에 전송되는 간격을 제어합니다. 기본 데이터 지연은 일반적인 화면 방향 변경을 모니터링하는 데 적합하며 200,000 마이크로초의 지연 시간을 사용합니다. SENSOR_DELAY_GAME (20,000마이크로초 지연 시간), SENSOR_DELAY_UI (60,000마이크로초 지연 시간), SENSOR_DELAY_FASTEST (0 마이크로초 지연 시간) 등 다른 데이터 지연을 지정할 수 있습니다. Android 3.0 (API 수준 11)부터 지연 시간을 절대 값 (마이크로초 단위)으로 지정할 수도 있습니다.

지정하는 지연은 추천 지연일 뿐입니다. Android 시스템 및 기타 애플리케이션에서 이러한 지연을 변경할 수 있습니다. 시스템에서 일반적으로 개발자가 지정한 것보다 더 작은 지연을 사용하므로 최대한 큰 지연을 지정해야 합니다. 즉, 애플리케이션의 요구를 충족하는 가장 느린 샘플링 레이트를 선택해야 합니다. 지연 시간을 더 길게 사용하면 프로세서에 더 낮은 부하가 적용되므로 전력이 더 적게 소모됩니다.

센서 프레임워크가 센서 이벤트를 애플리케이션에 전송하는 속도를 결정하는 공개 메서드는 없지만 각 센서 이벤트와 연결된 타임스탬프를 사용하여 여러 이벤트의 샘플링 레이트를 계산할 수 있습니다. 샘플링 레이트 (지연)를 설정한 후에는 변경하지 않아도 됩니다. 어떤 이유로든 지연을 변경해야 하는 경우 센서 리스너를 등록 취소하고 다시 등록해야 합니다.

또한 이 예에서는 onResume()onPause() 콜백 메서드를 사용하여 센서 이벤트 리스너를 등록 및 등록 취소한다는 점에 유의해야 합니다. 특히 활동이 일시중지된 경우에는 필요하지 않은 센서를 항상 사용 중지하는 것이 좋습니다. 그렇게 하지 않으면 단 몇 시간에 배터리가 소모될 수 있습니다. 일부 센서에서 상당한 전원이 필요하고 배터리를 빠르게 소모하기 때문입니다. 화면이 꺼져도 시스템이 센서를 자동으로 사용 중지하지 않습니다.

다양한 센서 구성 처리

Android에서는 기기에 표준 센서 구성을 지정하지 않습니다. 즉 기기 제조업체가 원하는 센서 구성을 Android 지원 기기에 통합할 수 있습니다. 따라서 기기에는 광범위한 구성의 다양한 센서를 포함할 수 있습니다. 애플리케이션이 특정 유형의 센서에 의존하는 경우 센서가 기기에 존재하여 앱이 실행될 수 있어야 합니다.

특정 센서가 기기에 존재하는지는 두 가지 방법으로 확인할 수 있습니다.

  • 런타임에 센서를 감지하고 애플리케이션 기능을 적절히 사용 설정 또는 중지합니다.
  • Google Play 필터를 사용하여 특정한 센서 구성의 기기를 타겟팅합니다.

각 방법은 다음 섹션에 설명되어 있습니다.

런타임에 센서 감지

애플리케이션에서 특정 유형의 센서를 사용하지만 이에 의존하지 않는 경우 센서 프레임워크를 사용하여 런타임에 센서를 감지한 다음 애플리케이션 기능을 적절히 사용 설정 또는 중지할 수 있습니다. 예를 들어 내비게이션 애플리케이션에서 온도 센서, 압력 센서, GPS 센서, 지자기장 센서를 사용하여 온도, 기압, 위치, 나침반 방위를 표시할 수 있습니다. 기기에 압력 센서가 없는 경우 센서 프레임워크를 사용하여 런타임에 압력 센서가 없음을 감지한 다음 압력을 표시하는 애플리케이션의 UI 부분을 사용 중지할 수 있습니다. 예를 들어 다음 코드는 기기에 압력 센서가 있는지 확인합니다.

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) {
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

자바

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

Google Play 필터를 사용하여 특정 센서 구성 타겟팅

Google Play에 애플리케이션을 게시하는 경우 매니페스트 파일에 <uses-feature> 요소를 사용하여 애플리케이션에 적절한 센서 구성이 없는 기기에서 애플리케이션을 필터링할 수 있습니다. <uses-feature> 요소에는 특정 센서의 존재 여부를 기반으로 애플리케이션을 필터링할 수 있는 여러 하드웨어 설명자가 있습니다. 가속도계, 기압계, 나침반 (지자기장), 자이로스코프, 조도 센서, 근접 센서를 나열할 수 있습니다. 다음은 가속도계가 없는 앱을 필터링하는 매니페스트 항목의 예입니다.

<uses-feature android:name="android.hardware.sensor.accelerometer"
              android:required="true" />

이 요소와 설명자를 애플리케이션의 매니페스트에 추가하면 사용자의 기기에 가속도계가 있는 경우에만 Google Play에서 사용자에게 애플리케이션이 표시됩니다.

애플리케이션이 특정 센서에 전적으로 의존하는 경우에만 설명자를 android:required="true"로 설정해야 합니다. 애플리케이션이 일부 기능에 센서를 사용하지만 여전히 센서 없이 실행되는 경우 센서를 <uses-feature> 요소에 나열하는 한편 설명자를 android:required="false"로 설정해야 합니다. 이렇게 하면 기기에 특정 센서가 없어도 기기에서 앱을 설치할 수 있습니다. 이 방법은 또한 프로젝트 관리 권장사항으로 애플리케이션에서 사용하는 기능을 추적하는 데 도움이 됩니다. 애플리케이션에서 특정 센서를 사용하지만 여전히 센서 없이 실행되는 경우 런타임에 센서를 감지하고 애플리케이션 기능을 적절히 사용 설정 또는 중지해야 합니다.

센서 좌표계

일반적으로 센서 프레임워크는 표준 3축 좌표계를 사용하여 데이터 값을 표현합니다. 대부분의 센서의 경우 좌표계는 기기가 기본 방향으로 유지될 때 기기의 화면을 기준으로 정의됩니다 (그림 1 참고). 기기가 기본 방향으로 유지될 때 X축은 가로축으로 오른쪽을 가리키고 Y축은 세로축으로 위쪽을 가리키며 Z축은 화면 바깥쪽을 가리킵니다. 이 시스템에서 화면 뒤의 좌표는 Z 값이 음수입니다. 이 좌표계는 다음 센서에서 사용됩니다.

그림 1. Sensor API에서 사용하는 (기기 기준) 좌표계

이 좌표계를 이해하는 데 있어 가장 중요한 점은 기기의 화면 방향이 변경될 때 축이 바뀌지 않는다는 것입니다. 즉 기기가 움직여도 센서의 좌표계가 변경되지 않습니다. 이 동작은 OpenGL 좌표계의 동작과 동일합니다.

또 한 가지 이해해야 하는 점은 애플리케이션에서 기기의 자연스러운(기본) 방향이 세로 모드라고 가정해서는 안 된다는 것입니다. 많은 태블릿 기기의 자연스러운 방향은 가로 모드입니다. 센서 좌표계는 항상 기기의 자연스러운 방향을 기반으로 합니다.

마지막으로 애플리케이션에서 센서 데이터를 화면 표시와 일치시키는 경우 getRotation() 메서드를 사용하여 화면 회전을 결정한 다음 remapCoordinateSystem() 메서드를 사용하여 센서 좌표를 화면 좌표로 매핑해야 합니다. 매니페스트에서 세로 모드 전용 표시를 지정하는 경우에도 이렇게 해야 합니다.

참고: 일부 센서 및 메서드에서는 기기의 기준 좌표계가 아니라 세계 좌표계를 기준으로 하는 좌표계를 사용합니다. 이러한 센서 및 메서드는 지구를 기준으로 기기 움직임 또는 기기 위치를 나타내는 데이터를 반환합니다. 자세한 내용은 getOrientation() 메서드, getRotationMatrix() 메서드, 방향 센서, 회전 벡터 센서를 참고하세요.

센서 비율 제한

잠재적으로 민감한 사용자 정보를 보호하기 위해 앱이 Android 12 (API 수준 31) 이상을 타겟팅하는 경우 시스템은 특정 움직임 감지 센서와 위치 센서의 데이터 새로고침 빈도를 제한합니다. 이 데이터에는 기기의 가속도계, 자이로스코프, 지자기장 센서에 기록된 값이 포함됩니다.

새로고침 빈도 제한은 센서 데이터에 액세스하는 방법에 따라 다릅니다.

앱이 더 높은 속도로 움직임 감지 센서 데이터를 수집해야 한다면 다음 코드 스니펫과 같이 HIGH_SAMPLING_RATE_SENSORS 권한을 선언해야 합니다. 이 권한을 선언하지 않고 앱이 더 높은 속도로 움직임 감지 센서 데이터를 수집하려고 하면 SecurityException이 발생합니다.

AndroidManifest.xml

<manifest ...>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <application ...>
        ...
    </application>
</manifest>

센서 액세스 및 사용에 관한 권장사항

센서 구현을 설계할 때는 이 섹션에서 설명하는 가이드라인을 따라야 합니다. 이 가이드라인은 센서 프레임워크를 사용하여 센서에 액세스하고 센서 데이터를 획득하는 모든 사용자에게 권장되는 권장사항입니다.

포그라운드에서만 센서 데이터 수집

Android 9 (API 수준 28) 이상을 실행하는 기기에서 백그라운드에서 실행되는 앱에는 다음과 같은 제한사항이 있습니다.

  • 가속도계 및 자이로스코프와 같이 연속 보고 모드를 사용하는 센서는 이벤트를 수신하지 않습니다.
  • 변경 시 또는 원샷 보고 모드를 사용하는 센서는 이벤트를 수신하지 않습니다.

이러한 제한사항을 고려하면 앱이 포그라운드에 있거나 포그라운드 서비스에 포함되어 있을 때 센서 이벤트를 감지하는 것이 가장 좋습니다.

센서 리스너 등록 취소

센서 사용을 완료했거나 센서 활동이 일시중지된 경우 센서의 리스너를 등록 취소해야 합니다. 센서 리스너가 등록되고 활동이 일시중지된 경우 센서를 등록 취소하지 않는 한 센서에서 계속 데이터를 획득하고 배터리 리소스를 사용합니다. 다음 코드는 onPause() 메서드를 사용하여 리스너를 등록 취소하는 방법을 보여줍니다.

Kotlin

private lateinit var sensorManager: SensorManager
...
override fun onPause() {
    super.onPause()
    sensorManager.unregisterListener(this)
}

자바

private SensorManager sensorManager;
...
@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
}

자세한 내용은 unregisterListener(SensorEventListener)를 참조하세요.

Android Emulator로 테스트

Android Emulator에는 가속도계, 주변 온도, 자기계, 근접, 조도 등의 센서를 테스트할 수 있는 가상 센서 컨트롤 집합이 포함되어 있습니다.

에뮬레이터는 SdkControllerSensor 앱을 실행하는 Android 기기와의 연결을 사용합니다. 이 앱은 Android 4.0 (API 수준 14) 이상을 실행하는 기기에서만 사용할 수 있습니다. Android 4.0을 실행하는 기기의 경우 버전 2가 설치되어 있어야 합니다. SdkControllerSensor 앱은 기기의 센서 변경사항을 모니터링하고 에뮬레이터로 전송합니다. 그런 다음 기기의 센서에서 수신한 새 값을 기반으로 에뮬레이터가 변환됩니다.

SdkControllerSensor 앱의 소스 코드는 다음 위치에서 볼 수 있습니다.

$ your-android-sdk-directory/tools/apps/SdkController

기기와 에뮬레이터 간에 데이터를 전송하려면 다음 단계를 따르세요.

  1. 기기에서 USB 디버깅이 사용 설정되어 있는지 확인합니다.
  2. USB 케이블을 사용하여 기기를 개발용 컴퓨터에 연결합니다.
  3. 기기에서 SdkControllerSensor 앱을 시작합니다.
  4. 앱에서 에뮬레이션할 센서를 선택합니다.
  5. 다음 adb 명령어를 실행합니다.

  6. $ adb forward tcp:1968 tcp:1968
    
  7. 에뮬레이터를 시작합니다. 이제 기기를 이동하여 에뮬레이터에 변환을 적용할 수 있습니다.

참고: 실제 기기를 움직여도 에뮬레이터가 변환되지 않으면 5단계의 adb 명령어를 다시 실행해 보세요.

자세한 내용은 Android Emulator 가이드를 참고하세요.

onSensorChanged() 메서드를 차단하지 않음

센서 데이터가 빠른 속도로 변경되어 시스템에서 onSensorChanged(SensorEvent) 메서드를 자주 호출할 수도 있습니다. onSensorChanged(SensorEvent) 메서드 내에서 최대한 적게 실행하여 차단하지 않는 것이 좋습니다. 애플리케이션에서 데이터를 필터링하거나 센서 데이터를 축소해야 한다면 onSensorChanged(SensorEvent) 메서드 외부에서 그 작업을 실행해야 합니다.

지원 중단된 메서드 또는 센서 유형 사용하지 않음

여러 메서드 및 상수가 지원 중단되었습니다. 특히 TYPE_ORIENTATION 센서 유형이 지원 중단되었습니다. 방향 데이터를 얻으려면 getOrientation() 메서드를 호출해야 합니다. TYPE_TEMPERATURE 센서 유형도 지원 중단되었습니다. Android 4.0을 실행하는 기기에서는 TYPE_AMBIENT_TEMPERATURE 센서 유형을 대신 사용해야 합니다.

센서를 사용하기 전에 확인

센서에서 데이터를 얻으려고 시도하기 전에 항상 기기에 센서가 존재하는지 확인하세요. 단순히 센서가 자주 사용된다고 해서 존재한다고 가정하지 마세요. 기기 제조업체가 자사의 기기에 특정 센서를 제공할 의무는 없습니다.

센서 지연 시간을 신중하게 선택

registerListener() 메서드를 사용하여 센서를 등록하는 경우 애플리케이션 또는 사용 사례에 적합한 전송률을 선택해야 합니다. 센서는 매우 빠른 속도로 데이터를 제공할 수 있습니다. 시스템에서 불필요한 추가 데이터를 전송하도록 허용하면 시스템 리소스가 낭비되고 배터리 전원이 소모됩니다.