iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 27
0
Software Development

Kotlin 30 天,通過每天一個小 demo 學習 Android 開發系列 第 27

Kotlin 開發第 27 天 ShakeShake ( SensorManager )

ShakeShake

這次通過設備的 Sensor 判斷使用者是否有搖晃手機(類似微信的搖一搖功能)

偵測手機搖動狀況
搖晃後更換圖片、震動手機
設定 2秒內只發動一次事件(搖晃過程會一直拿到 Sensor 數據,但不希望因此在短時間內連續震動或換圖)


ShakeShake

通過 SensorManager 來獲取 Sensor,Vibrator 來震動手機。


SensorManager

要使用 Sensor 的步驟很簡短,和 system 要到 SensorManager,在要到對應的 sensor.

然後 register Listener 用來接收 sensor 拿到的數據

val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL)

SensorEventListener

這裡以 Accelerometer 為例,當使用者搖動手機的時候,我們就執行 shakeHandler()

private val sensorListener = object:SensorEventListener {
    override fun onAccuracyChanged(p0: Sensor?, p1: Int) {}

    override fun onSensorChanged(event: SensorEvent?) {
        if(event != null){
            val xValue = Math.abs(event.values[0]) // 加速度 - X 軸方向
            val yValue = Math.abs(event.values[1]) // 加速度 - Y 軸方向
            val zValue = Math.abs(event.values[2]) // 加速度 - Z 軸方向
            if (xValue > 20 || yValue > 20 || zValue > 20) {
                shakeHandler()
            }
        }
    }

}

ShakeHandler

通過 isChangingPhoto 這個自己定屬性,來防止因為搖動過程中多次觸發事件。

當我們接收到搖動事件的時候,
就先將 isChangingPhoto 改為 true,並開始更換圖片和震動手機( changImage() / doVibrate())

然後執行一個 Handler 相隔一秒以後在將 isChangingPhoto 改為 false.

private fun shakeHandler() {
    if(isChangingPhoto){
        return
    }

    isChangingPhoto = true

    changeImage()
    doVibrate()

    Handler().postDelayed({
        isChangingPhoto = false
    }, 1000)
}

private fun doVibrate() {
    if(Build.VERSION.SDK_INT >= 26){
        vibrator.vibrate(VibrationEffect.createOneShot(100, 10))
    } else {
        vibrator.vibrate(100)
    }
}

private fun changeImage() {
    when(currentImageNumber){
        0 -> layout_landImageView.setImageResource(images[1])
        1 -> layout_landImageView.setImageResource(images[2])
        2 -> layout_landImageView.setImageResource(images[3])
        3 -> layout_landImageView.setImageResource(images[4])
        4 -> layout_landImageView.setImageResource(images[0])
    }

    if(currentImageNumber != 4){
        currentImageNumber += 1
    } else {
        currentImageNumber = 0
    }

}

SensorList

和 iOS 開發環境很不一樣的是,Android 的硬件設備都來自各種不同的廠商,但在 Android 中有定義 20幾種傳感器。

其中常用的應該是陀螺儀、加速計、方向傳感器、重力傳感器等。

public static final int TYPE_ACCELEROMETER = 1;
public static final int TYPE_ACCELEROMETER_UNCALIBRATED = 35;
public static final int TYPE_AMBIENT_TEMPERATURE = 13;
public static final int TYPE_GAME_ROTATION_VECTOR = 15;
public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
public static final int TYPE_GRAVITY = 9;
public static final int TYPE_GYROSCOPE = 4;
public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
public static final int TYPE_HEART_BEAT = 31;
public static final int TYPE_HEART_RATE = 21;
public static final int TYPE_LIGHT = 5;
public static final int TYPE_LINEAR_ACCELERATION = 10;
public static final int TYPE_LOW_LATENCY_OFFBODY_DETECT = 34;
public static final int TYPE_MAGNETIC_FIELD = 2;
public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
public static final int TYPE_MOTION_DETECT = 30;
public static final int TYPE_POSE_6DOF = 28;
public static final int TYPE_PRESSURE = 6;
public static final int TYPE_PROXIMITY = 8;
public static final int TYPE_RELATIVE_HUMIDITY = 12;
public static final int TYPE_ROTATION_VECTOR = 11;
public static final int TYPE_SIGNIFICANT_MOTION = 17;
public static final int TYPE_STATIONARY_DETECT = 29;
public static final int TYPE_STEP_COUNTER = 19;
public static final int TYPE_STEP_DETECTOR = 18;

我們可以通過 getSensorList 來拿到這個設備支援的 Sensor

比如我們這裡印出 sensor 類型、廠商名稱、版本

val allSensors = sensorManager.getSensorList(Sensor.TYPE_ALL)
for(sensor in allSensors){
    Log.i("sensors", "${sensor.name} - ${sensor.vendor} - ${sensor.version}")

}

這是紅米手機的一個例子

Accelerometer - BOSCH - 2062500
Magnetometer - Yamaha - 35193090
Magnetometer Uncalibrated - Yamaha - 35193090
ALSPS - LiteOn - 2
......

Log

我們經常通過 android.util.Log 來印出一些資訊,而常見的有這幾個 Log 方法

Log.v - v 代表 verbose - 任何信息都會輸出
Log.d - d 代表 debug - 輸出調試信息
Log.i - i 代表 information
Log.w - w 代表 warning - 輸出警告資訊
Log.e -  e 代表 error - 輸出警告資訊。


參考


上一篇
Kotlin 開發第 26 天 ActionSend ( Intent-Filter )
下一篇
Kotlin 開發第 28 天 Parks ( ViewPager + TabLayout )
系列文
Kotlin 30 天,通過每天一個小 demo 學習 Android 開發30

尚未有邦友留言

立即登入留言