Sensors APIは、デバイスのハードウェアセンサーにアクセスするためのAndroidプラットフォームインターフェースです。APIは、加速度計、ジャイロスコープ、磁力計、光センサーなどのセンサーからデータを取得する統一された方法を提供します。Google、2026年によると、最新のAndroidデバイスの95%以上が少なくとも3種類のセンサーを搭載しており、コンテキスト認識型アプリケーション開発の幅広い可能性を開いています。
主要なポイント
Sensors APIは、Android Frameworkのソフトウェアインターフェースであり、開発者にモバイルデバイスのハードウェアセンサーへのアクセスを提供します。APIはバージョン1.0からAndroid SDKの一部であり、android.hardwareパッケージから利用できます。このインターフェースは、Qualcomm、MediaTek、Samsung Exynosなどの異なるメーカーのセンサー実装間の違いを抽象化し、センサー操作の統一モデルを提供します。
APIは3つの主要な操作を可能にします:利用可能なセンサーのリスト取得、データ受信用リスナーの登録、更新レートの管理。SensorManagerはすべての操作の中心的なアクセスポイントとして機能します。システムはonSensorChangedコールバックを介してアプリケーションに通知し、float値の配列を持つSensorEventオブジェクトを渡します。
Androidの歴史を通じて、APIはいくつかの発展段階を経てきました。バージョン2.3(Gingerbread)ではバッチ処理(消費電力を抑えるためのセンサイベントのグループ化)が導入されました。Android 4.0(Ice Cream Sandwich)では仮想センサーのGravityとLinear Accelerationが追加されました。Android 8.0以降、システムはプライバシー強化のためセンサーへのバックグラウンドアクセスを制限しました。
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensorList: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
sensorList.forEach { sensor ->
Log.d("センサー", "${sensor.name} — ${sensor.type}")
}
すべてのデバイスが同じセンサーセットを備えているわけではありません。アプリケーションはリスナーを登録する前に、特定のセンサーの利用可能性を確認する必要があります。Androidエミュレータは限られたセンサーセット(加速度計と磁力計)のみをサポートします。他のセンサーのテストには物理デバイスが必要です。Android 12以降、アプリケーションはマニフェストでセンサーの使用を宣言する必要があります。
AndroidはすべてのセンサーをMotion、Position、Environmentの3つのカテゴリに分類します。Motionセンサーには加速度計、ジャイロスコープ、歩数計が含まれます。Positionセンサーには磁力計と方位が含まれます。Environmentセンサーには光、圧力、温度、湿度が含まれます。
| カテゴリ | センサー | タイプ(定数) | 物理/仮想 |
|---|---|---|---|
| Motion | 加速度計 | TYPE_ACCELEROMETER | 物理 |
| Motion | ジャイロスコープ | TYPE_GYROSCOPE | 物理 |
| Motion | 歩数計 | TYPE_STEP_COUNTER | 物理 |
| Motion | Gravity | TYPE_GRAVITY | 仮想 |
| Position | 磁力計 | TYPE_MAGNETIC_FIELD | 物理 |
| Position | Rotation Vector | TYPE_ROTATION_VECTOR | 仮想 |
| Environment | 光 | TYPE_LIGHT | 物理 |
| Environment | 圧力 | TYPE_PRESSURE | 物理 |
加速度計は3軸(X、Y、Z)に沿ってm/s²単位で加速度を測定します。値には重力(静止時のZ軸方向で9.8 m/s²)が含まれます。ジャイロスコープは各軸周りのデバイスの回転速度である角速度をrad/s単位で測定します。これら2つのセンサーの組み合わせは、ナビゲーション、ゲーム、ARアプリケーションで使用されます。
class SensorActivity : Activity(), SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
textView.text = "X: $x, Y: $y, Z: $z"
}
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
}
磁力計(TYPE_MAGNETIC_FIELD)は3軸に沿って磁場をマイクロテスラ(µT)単位で測定します。デジタルコンパスとして使用され、加速度計と組み合わせてデバイスの方位角を決定します。Rotation Vectorは、ジャイロスコープ、加速度計、磁力計のデータを融合して正確な方位を決定する仮想センサーです。
光センサー(TYPE_LIGHT)は周囲光レベルをルクス(lx)単位で測定します。自動画面輝度調整に使用されます。圧力センサー(TYPE_PRESSURE)は気圧をヘクトパスカル(hPa)単位で測定し、ナビゲーションアプリケーションで海抜高度の決定に使用されます。
Sensors APIはクライアント-サーバーアーキテクチャ上に構築されています。アプリケーションがクライアント、SensorManagerがAndroidシステムサービスとして機能します。アプリケーションがregisterListenerを介してリスナーを登録すると、SensorManagerはHAL(ハードウェア抽象化層)— Linuxカーネルレベルで動作する低レベルセンサードライバーと通信します。
HALドライバーはハードウェアチップから生データを受信し、ノイズをフィルタリングして、スタックを上に—SensorService(システムプロセス)を経由してアプリケーションに渡します。データはfloat値の配列valuesとナノ秒単位のタイムスタンプを含むSensorEventオブジェクトとして渡されます。イベントレートは選択された配信モードに依存します。
リスナー登録時に、開発者は定数SENSOR_DELAY_NORMAL(200 ms)、SENSOR_DELAY_UI(60 ms)、SENSOR_DELAY_GAME(20 ms)、SENSOR_DELAY_FASTEST(0 ms — 最大レート)を使用してイベント間の希望する遅延を指定します。実際のレートは異なる場合があります—システムが消費電力を最適化します。
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager.registerListener(
this,
sensor,
SensorManager.SENSOR_DELAY_GAME
)
Android 2.3以降、センサーはバッチモードをサポートしています—イベントはFIFOバッファに蓄積され、1つのバッチで配信されます。これによりプロセッサはスリープモードをより長く維持でき、消費電力を最大60%削減します。バッファサイズはセンサーチップに依存し、Sensor.fifoMaxEventCountフィールドで指定されます。
SensorManagerはgetSystemService(Context.SENSOR_SERVICE)を介して利用可能なシステムサービスです。センサーリストの取得、特定のデフォルトセンサーの取得、リスナーの登録/解除のメソッドを提供します。SensorManagerはシングルトンです—アプリケーション全体で1つのインスタンスです。
センサーを使用する前に、その利用可能性を確認する必要があります。getDefaultSensor(type)メソッドは、センサーがデバイスに存在しない場合nullを返します。確認せずにnullを取得すると、リスナー登録時にNullPointerExceptionが発生します。getSensorList(type)メソッドはすべてのセンサーのリストを返します。
fun checkSensorAvailability(type: Int): Boolean {
val sensorManager =
getSystemService(Context.SENSOR_SERVICE) as SensorManager
return sensorManager.getDefaultSensor(type) != null
}
// 使用法:
if (checkSensorAvailability(Sensor.TYPE_GYROSCOPE)) {
Log.d("センサー", "ジャイロスコープ利用可能")
}
リスナーはregisterListener(listener, sensor, delay)を介して登録されます。重要:onPause()メソッドでunregisterListener(listener)を介してリスナーを解除する必要があります。これを行わないと、アプリケーションはバックグラウンドでもセンサイベントを受信し続け、バッテリーを消耗します。Android 8+は未解除のリスナーについてlogcatに警告を表示します。
onAccuracyChanged(sensor, accuracy)メソッドはセンサーの精度が変更されたときに呼び出されます。値:SENSOR_STATUS_ACCURACY_HIGH、MEDIUM、LOW、UNRELIABLE。UNRELIABLEを受信した場合、精度が回復するまでセンサーデータは無視されるべきです。例えば、磁力計はキャリブレーション(デバイスを8の字に振る)が必要です。
Kotlinを使用したAndroidアプリケーションでのSensors APIの実用的な例を見てみましょう。最初の例 — 加速度計を使用した画面の向きの決定。2番目 — キャリブレーション付き磁力計データの読み取り。3番目 — 歩数計を使用した歩数検出。
加速度計と磁力計の組み合わせを使用して向きを決定します。SensorManager.getRotationMatrix()メソッドは回転行列を計算し、getOrientation()はpitch、roll、azimuthの角度を抽出します。Azimuth(方位角) — ラジアン単位の磁北に対する角度。
val gravity = FloatArray(3)
val geomagnetic = FloatArray(3)
val rotationMatrix = FloatArray(9)
val orientation = FloatArray(3)
SensorManager.getRotationMatrix(
rotationMatrix, null, gravity, geomagnetic
)
SensorManager.getOrientation(rotationMatrix, orientation)
// orientation[0] — azimuth, [1] — pitch, [2] — roll
val azimuthDeg = Math.toDegrees(orientation[0].toDouble())
歩数計(TYPE_STEP_COUNTER)は、最後のデバイス再起動以降のユーザーの総歩数を返します。センサーはハードウェアレベルで動作し、アプリケーションが実行されていない場合でもアクティブです。セッションあたりの歩数を取得するには、初期値を保存し、差を計算する必要があります。
var initialSteps = 0
var isInitialized = false
override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_STEP_COUNTER) {
if (!isInitialized) {
initialSteps = event.values[0].toInt()
isInitialized = true
}
val currentSteps = event.values[0].toInt()
val sessionSteps = currentSteps - initialSteps
Log.d("歩数", "セッションあたりの歩数: $sessionSteps")
}
}
光センサーはインターフェースを環境条件に適応させることができます。低照度(10 lx未満)ではダークモードに切り替えられます。明るい日光(10000 lx超)ではコントラストを上げられます。ノイズフィルタリングには、最後の5値の移動平均が使用されます。
Androidは直接のハードウェア同等物を持たないいくつかの仮想センサーを提供します。仮想センサーは物理センサーの組み合わせに基づいて読み取り値を計算します。これにより開発者の負担が軽減されます—システム自体がデータフュージョンアルゴリズムを実装します。
Gravity(TYPE_GRAVITY)センサーはローパスフィルターを使用して加速度計の読み取り値から重力成分を抽出します。Linear Acceleration(TYPE_LINEAR_ACCELERATION)は逆に重力を除去し、デバイスの線形加速度のみを残します。GravityとLinear Accelerationの合計は加速度計の生の読み取り値になります。
Rotation Vector — 最も複雑な仮想センサー。ジャイロスコープ(高周波変化)、加速度計(重力ベクトル)、磁力計(北に対する方位)からのデータを組み合わせます。結果は空間内のデバイスの絶対的な向きを記述するクォータニオンです。ARアプリケーションやVRヘッドセットで使用されます。
Game Rotation Vector — 磁力計を使用しないRotation Vectorの簡略版。方位精度は低くなりますが、更新レートと安定性が向上します。絶対的な北に対する方位よりも低遅延が重要なゲームに推奨されます。
センサーはデバイスで最も電力を消費するコンポーネントの一部です。加速度計とジャイロスコープを最大ポーリングレートで使用すると、3–4時間の連続動作でバッテリーを消耗させる可能性があります。センサー使用の最適化は、Sensors APIを使用するすべてのアプリケーションにとって重要なタスクです。
不必要にSENSOR_DELAY_FASTESTを使用しないでください。UIアニメーションにはSENSOR_DELAY_UI(60 ms)で十分です。画面の向きの検出にはSENSOR_DELAY_NORMAL(200 ms)で十分です。レートが高いほど、プロセッサはアクティブ状態でより多くの時間を費やします。NORMALとFASTESTの間では消費電力が最大10倍異なります。
Android 8.0(API 26)以降、バックグラウンドアプリケーションは低減されたレートでセンサイベントを受信します。Android 12+では、MotionおよびPositionセンサーへのバックグラウンドアクセスにBODY_SENSORS_BACKGROUND権限が必要です。アプリケーションがバックグラウンドに移行する際にリスナーを解除してください—これによりデバイスのバッテリー寿命が延びます。
registerListener(listener, sensor, delay, maxReportLatencyUs)メソッドを介してバッチ処理を使用します。maxReportLatencyUsパラメータはマイクロ秒単位の最大イベント配信遅延を設定します。1000000(1秒)の値では、イベントはセンサーのFIFOバッファに蓄積され、1秒に1回配信されます—プロセッサの起動頻度が低下します。
よくある質問
最小セットは加速度計と磁力計です。これら2つのセンサーは95%以上のデバイスに搭載されています。ジャイロスコープ、光センサー、近接センサーは70–80%の最新モデルに搭載されています。その他のセンサー(圧力、温度、湿度、歩数計)はあまり一般的ではなく、デバイスの価格帯に依存します。
TYPE_ACCELEROMETERは重力を含む完全な加速度(9.8 m/s²)を返します。TYPE_LINEAR_ACCELERATIONは重力を除いた加速度、つまりデバイスの運動加速度のみを返します。デバイスが静止している場合、加速度計はZ軸に沿って9.8 m/s²を示しますが、Linear Accelerationは全軸で0を示します。
適切な定数とともにgetPackageManager().hasSystemFeature()を使用します:FEATURE_SENSOR_ACCELEROMETER、FEATURE_SENSOR_GYROSCOPE、FEATURE_SENSOR_PROXIMITYなど。別の方法として、getDefaultSensor(type)を呼び出し、結果がnullかどうかを確認します。初期化時の確認には最初の方法が推奨されます。
センサーの生データにはノイズが含まれます。平滑化にはローパスフィルターを使用します:newValue = alpha * rawValue + (1 — alpha) * previousValue。alpha係数0.1–0.3は応答性と平滑性の良いバランスを提供します。ジャイロスコープにはゼロドリフト除去のためのハイパスフィルターも適用されます。
はい、ただし制限があります。Android 8.0以降、バックグラウンドアプリケーションのセンサイベントレートは低下します。Android 12以降、バックグラウンドでのセンサーアクセスにはBODY_SENSORS_BACKGROUND権限が必要です。バックグラウンド作業には、通知付きのForeground Serviceの使用が推奨されます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。