달달한 스토리

728x90
반응형

 

미리 출처를 남깁니다.

 

요즘 개발하는 정대리님의 유익한 유튜브를 보면서 코틀린을 익히는 중입니다.

 

항상 감사합니다.

 

출처

https://www.youtube.com/channel/UCutO2H_AVmWHbzvE92rpxjA

 

개발하는 정대리

한국에서 개발자로 살아남기! 예전에 저처럼 프로그래머가 되고 싶지만 그 길을 몰라 해매는 분들에게 도움 되고자 이 채널을 운영하기 시작했습니다. 프로그램에 관심 있는 분들이나 취업 준

www.youtube.com


해결법

 

사실 직접적인 이해보다는

 

스택 오버 플로우에서 가져온 코드를 그대로 사용했다는 점이 크기 때문에

 

자세히 코드에 대해 이해하지는 못하고 있다.

 

중요한 흐름만 파악해놓은 상태에서 코드에 간략한 소개만 하겠다.

 

정대리님의 영상을 보고 나서, X, Y, Z 축에 각각에 값을

 

나오게 하였으며, 흔들때마다 호출되는 메서드에 

 

핸들러를 달아서 일정 흔듬(?)이 기준치가 넘었을 때,

 

웃는 사진을 화난 사진으로 나타내게 하였다.

 

우선 코드를 살펴보자.

 

class MainActivity : AppCompatActivity(), SensorEventListener {
    var mbinding: ActivityMainBinding? = null
    val binding get() = mbinding!!
    
    val TAG: String = "로그"

    private var accel: Float = 0.0f //초기
    private var accelCurrent: Float = 0.0f //이동하는 치수
    private var accelLast: Float = 0.0f
    
    //당장이 아니라 나중에 값을 넣겠다. 온크레이트 이후에 설정을 넣겠다. 
    private lateinit var sensorManager: SensorManager
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mbinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        Log.d(TAG, "MainActivity - onCreate() called")

        //센서 매니저를 설정한다.
        this.sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

        accel = 10f
        accelCurrent = SensorManager.GRAVITY_EARTH //지구 중력값 주기
        accelLast = SensorManager.GRAVITY_EARTH

    }

    //흔들었을때 센서 감지
    override fun onSensorChanged(event: SensorEvent?) {
        Log.d(TAG, "MainActivity - onSensorChanged() called")

        val x:Float = event?.values?.get(0) as Float
        val y:Float = event?.values?.get(0) as Float
        val z:Float = event?.values?.get(0) as Float

        binding.x.text = "X: " + x.toInt().toString()
        binding.y.text = "Y: " + y.toInt().toString()
        binding.z.text = "Z: " + z.toInt().toString()

        accelLast = accelCurrent
        accelCurrent = sqrt((x * x + y * y + z * z).toDouble()).toFloat()

        val delta: Float = accelCurrent - accelLast

        accel = accel * 0.9f + delta

        //액셀 치수가 30이 넘어가면 흔들었다고 휴대폰이 판단한다.
        if(accel > 30){
            Log.d(TAG, "흔들었다.")

            //화난얼굴을 보여주고 1초뒤에 웃는 얼굴을 보여준다.
            binding.smile.setImageResource(R.drawable.ic_free_icon_angry_187140) //화난 얼굴

            //웃는 얼굴
            Handler(Looper.myLooper()!!).postDelayed({
                binding.smile.setImageResource(R.drawable.ic_free_icon_joke_185034) //웃는 얼굴
            }, 1000L)
        }
    }
	//센서에 정확도 변경되면 호출된다.
    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
        Log.d(TAG, "MainActivity - onAccuracyChanged() called")
    }

    //단말기가 켜졌을 때, 센서매니저 리스너 실행
    override fun onResume() {
        Log.d(TAG, "MainActivity - onResume() called")
        sensorManager.registerListener(this, sensorManager
            .getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
            ,SensorManager.SENSOR_DELAY_NORMAL)
        super.onResume()
    }

    //휴대폰이 꺼졌을때는 매니저를 꺼준다.
    override fun onPause() {
        sensorManager.unregisterListener(this)
        super.onPause()
    }
}

코드에 설명을 써놓았지만,

 

내가 이해하는 어느 정도 수준으로 말하자면,

 

class MainActivity : AppCompatActivity(), SensorEventListener {

    ...
    }

클래스 옆에 임플리먼트로 SensorEventListener를 달아줌으로써,

 

this를 사용했을 때, 리스너 객체를 참조하여 사용할 수 있게 만들어 준다.

 

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mbinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root) 
 
 //센서 매니저를 설정한다.
        this.sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

        accel = 10f
        accelCurrent = SensorManager.GRAVITY_EARTH //지구 중력값 주기
        accelLast = SensorManager.GRAVITY_EARTH
        
        }

onCreate에 센서 매니저를 설정해준다.

 

그리고 임플리먼트로 SensorEventListener를 달아주면,

 

두 메서드를 임플리먼트 해줄 수 있다.

 

onSensorChangedonAccuracyChanged이다.

 

전자는 흔들었을 센서를 감자하여, SensorEvent가 파라미터로 전달이 되고,

 

후자는 센서에 정확도에 의해 변경되면 호출이 된다 하는데,

 

사용하지 않아서 잘 모르겠다.

 

알게 되면 글을 올려보겠다.

 

여기서는 사용하지 않았다.

 

 

onSensorChanged에 X, Y, Z의 값을 TextView에 실시간으로 넣게 하였고,

 

accel이 흔들림의 값인데,

 

이 값이 일정 값(30)을 넘어가면, 적당히 흔들었다고 판단되기 때문에

 

if문에 의해 사진이 변경될 것이다.

 

사진이 변경되는 시점을 더 자세히 관찰하기 위한 딜레이로

 

핸들러를 사용하였다.

 

//흔들었을때 센서 감지
    override fun onSensorChanged(event: SensorEvent?) {
        Log.d(TAG, "MainActivity - onSensorChanged() called")

        val x:Float = event?.values?.get(0) as Float
        val y:Float = event?.values?.get(0) as Float
        val z:Float = event?.values?.get(0) as Float

        binding.x.text = "X: " + x.toInt().toString()
        binding.y.text = "Y: " + y.toInt().toString()
        binding.z.text = "Z: " + z.toInt().toString()

        accelLast = accelCurrent
        accelCurrent = sqrt((x * x + y * y + z * z).toDouble()).toFloat()

        val delta: Float = accelCurrent - accelLast

        accel = accel * 0.9f + delta

        //액셀 치수가 30이 넘어가면 흔들었다고 휴대폰이 판단한다.
        if(accel > 30){
            Log.d(TAG, "흔들었다.")

            //화난얼굴을 보여주고 1초뒤에 웃는 얼굴을 보여준다.
            binding.smile.setImageResource(R.drawable.ic_free_icon_angry_187140) //화난 얼굴

            //웃는 얼굴
            Handler(Looper.myLooper()!!).postDelayed({
                binding.smile.setImageResource(R.drawable.ic_free_icon_joke_185034) //웃는 얼굴
            }, 1000L)
        }
    }

 

그러고 나서 아래와 같이 onResume에다가 

 

단말기가 실행되었을 때, 센서 매니저 리스너를 실행하는 코드를 짜고,

 

이 액티비티를 나가려고 할 때, (정확히는 다른 액티비티가 보일 때) = > onPause()

 

가 실행이 될 때, 센서 매니저를 꺼줘야 하므로,(중복실행 및 메모리 손실 방지)

 

onPause()에 센서매니저 리스너를 꺼준다.

 

//휴대폰이 꺼졌을때는 매니저를 꺼준다.
    override fun onPause() {
        sensorManager.unregisterListener(this)
        super.onPause()
    }

아래는 xml 코드이다.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/x"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="X: "
        android:textSize="40dp" />

    <TextView
        android:id="@+id/y"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Y: "
        android:textSize="40dp" />

    <TextView
        android:id="@+id/z"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Z: "
        android:textSize="40dp" />

    <ImageView
        android:id="@+id/smile"
        android:padding="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_free_icon_joke_185034"/>


</LinearLayout>

이렇게 코드를 작성하면,

 

아래와 같이 흔들 때 웃는 표정 사진이 화난 사진 표정으로 바뀌는 것을 볼 수 있다.

 

다른 기능에 덧붙여 잘 활용하길 바란다.

 

전체 코드는 깃허브에 올려두었다

728x90
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading