LoginSignup
7
8

More than 3 years have passed since last update.

Kotlin&LiveDataで端末の向きを取得する処理を書いてみた

Last updated at Posted at 2018-06-01

Androidでデバイスの向きを取得するOrientation SensorはAndroid 2.2で非推奨となっており、現在は代わりに加速度センサーと磁気センサーを使って向きを計算する方法が推奨されています。
これを実装するコードはドキュメントに書かれているのですが、KotlinでやりたかったのとLiveDataを使ってより簡潔に実装したかったので、やってみました。

できあがったコードがこちらになります。

import androidx.lifecycle.LiveData
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager

// 向き情報を格納するクラス
data class Orientation(
        val azimuth: Float,
        val pitch: Float,
        val roll: Float
)

class OrientationLiveData(
        context: Context,
        private val sensorDelay: Int = SensorManager.SENSOR_DELAY_UI)
    : LiveData<Orientation>(), SensorEventListener {

    private val mSensorManager: SensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
    private val accelerometer: Sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    private val magneticField: Sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)

    private val mAccelerometerReading = FloatArray(3)
    private val mMagnetometerReading = FloatArray(3)

    private val mRotationMatrix = FloatArray(9)
    private val mOrientationAngles = FloatArray(3)

    override fun onActive() {
        super.onActive()

        mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL, sensorDelay)
        mSensorManager.registerListener(this, magneticField, SensorManager.SENSOR_DELAY_NORMAL, sensorDelay)
    }

    override fun onInactive() {
        super.onInactive()
        mSensorManager.unregisterListener(this)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}

    override fun onSensorChanged(event: SensorEvent) {

        if (event.sensor == accelerometer) {
            System.arraycopy(event.values, 0, mAccelerometerReading, 0, mAccelerometerReading.size)
        } else if (event.sensor == magneticField) {
            System.arraycopy(event.values, 0, mMagnetometerReading, 0, mMagnetometerReading.size)
        }

        updateOrientationAngles()

        value = Orientation(mOrientationAngles[0], mOrientationAngles[1], mOrientationAngles[2])
    }

    private fun updateOrientationAngles() {
        SensorManager.getRotationMatrix(mRotationMatrix, null, mAccelerometerReading, mMagnetometerReading)
        SensorManager.getOrientation(mRotationMatrix, mOrientationAngles)
    }
}

ほぼ元のドキュメントのコードをそのまま使っていますが、ActivityのライフサイクルコールバックをLiveData用に置き換えています。
このOrientationLiveDataを利用する側のコードは以下のようになります。

import androidx.lifecycle.Observer
import android.os.Bundle
import android.support.v7.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

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

        OrientationLiveData(this).observe(this, Observer { orientation ->

            if (orientation == null) return@Observer

            // orientation.azimuth
            // orientation.pitch
            // orientation.roll
            // で処理を行う
        })
    }

}

かんたん!!!

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8