센서 개요

대부분의 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를 사용하여 두 가지 기본 작업을 실행합니다.

  • 센서 및 센서 기능 식별

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

  • 센서 이벤트 모니터링

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

센서 사용 가능 여부

센서 사용 가능 여부는 기기마다 다르지만 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

Java

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

이제 getSensorList() 메서드를 호출하고 TYPE_ALL 상수를 사용하여 기기의 모든 센서 목록을 가져올 수 있습니다. 예:

Kotlin

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

Java

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

Java

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

Java

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 파일에서 sensor_data로 정의된 TextView에 원시 센서 데이터를 표시합니다.

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

Java

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

Java

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. 센서 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)
}

Java

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() 메서드로 센서를 등록할 때는 애플리케이션 또는 사용 사례에 적합한 전송 속도를 선택해야 합니다. 센서는 매우 빠른 속도로 데이터를 제공할 수 있습니다. 시스템이 필요하지 않은 추가 데이터를 전송하도록 허용하면 시스템 리소스가 낭비되고 배터리 전원이 사용됩니다.