본문 바로가기
ⓢⓣⓤⓓⓨ/ⓐⓝⓓⓡⓞⓘⓓⓢⓣⓤⓓⓘⓞ

[Kotlin] 타이머 만들기

by heaven00 2021. 9. 4.
728x90

 

 

이번 코드를 통해 chronometer과  elapsedRealtime을 확실히 이해할 수 있었다.

chronometer을 사용하니 start와 stop함수가 내장되어 있어서 편하게 코드를 짤 수 있었다!

 

 


 

chronometer: 타이머 기능을 구현할 수 있는 위젯

elapsedRealtime: 부팅 이후의 밀리초를 리턴. (절전 모드에서 보낸 시간 포함) 사용자가 현재 시간을 수정해도 영향을 받지 않으므로 유용하고 편리하게 사용 가능 

 

결과 화면

 

 

 

타이머 만드는 순서

 

(1) 뷰바인딩 적용

  - 저번에 내 포스팅을 참고하면 쉽다!  

  - build.gradle(Module)의 android 밑에 buildFeatures { viewBinding true } 작성 후, sync now

https://heaven0713.tistory.com/43?category=1001160 

 

[Kotlin] 뷰바인딩 (코틀린 시작 전 알아야 할 점)

원래 나는 안드로이드 개발을 자바로만 해왔다 모바일앱프로그램을 자바로 배우기도했고,,, 근데 이제 추세가 코틀린으로 기울고 있는 것 같고 코틀린의 장점을 점점 알게 되어서 공부를 시작

heaven0713.tistory.com

 

 

 

(2) 메인 xml 디자인 (출력화면)

 - 초가 출력될 화면과 버튼의 위치를 코딩해준다

 

 

(3) MainActivity 코딩

 - 각 버튼을 눌렀을 때 나타날 이벤트를 코딩해준다 (시작, 멈춤, 초기화)

 

 

 

 

 

 

코드 작성

 

(2) 메인 xml 디자인

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".MainActivity">

    <Chronometer
        android:id="@+id/chronometer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="200dp"
        android:gravity="center_horizontal"
        android:textSize="60dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="70dp">

        <Button
            android:id="@+id/startBtn"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="Start"
            android:textColor="#FFFFFF"
            android:textStyle="bold"/>

        <Button
            android:id="@+id/stopBtn"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="Stop"
            android:textColor="#FFFFFF"
            android:textStyle="bold"
            android:layout_marginLeft="25dp"
            android:enabled="false"/>

        <Button
            android:id="@+id/resetBtn"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="Reset"
            android:textColor="#FFFFFF"
            android:textStyle="bold"
            android:layout_marginLeft="25dp"
            android:enabled="false"/>

    </LinearLayout>

</RelativeLayout>

 

 

 

 

(3) MainActivity 코딩

 

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.SystemClock
import android.view.KeyEvent
import android.widget.Toast
import com.example.myapplication.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    //뒤로가기 버튼 누른 시각 저장
    var initTime = 0L

    //멈춘 시각 저장
    var pauseTime = 0L

    private var mBinding: ActivityMainBinding?= null
    private val binding get() = mBinding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //바인딩 초기화
        mBinding = ActivityMainBinding.inflate(layoutInflater)

        // 생성된 뷰 액티비티에 표시시
        setContentView(binding.root)

        // elapsedRealtime: 부팅 이후의 밀리초를 리턴 (절전 모드에서 보낸 시간 포함)
        // 사용자가 현재시간을 수정해도 영향 받지 않음
        binding.startBtn.setOnClickListener {
            binding.chronometer.base = SystemClock.elapsedRealtime() + pauseTime
            binding.chronometer.start()

            //버튼 표시 여부 조정
            binding.stopBtn.isEnabled = true
            binding.resetBtn.isEnabled = true
            binding.startBtn.isEnabled = false
        }

        binding.stopBtn.setOnClickListener {
            pauseTime = binding.chronometer.base - SystemClock.elapsedRealtime()
            binding.chronometer.stop()

            //버튼 표시 여부 조정
            binding.stopBtn.isEnabled = false
            binding.resetBtn.isEnabled = true
            binding.startBtn.isEnabled = true
        }


        binding.resetBtn.setOnClickListener {
            pauseTime = 0L
            binding.chronometer.base = SystemClock.elapsedRealtime()
            binding.chronometer.stop()

            //버튼 표시 여부 조정
            binding.stopBtn.isEnabled = false
            binding.resetBtn.isEnabled = false
            binding.startBtn.isEnabled = true
        }



    }

    // 뒤로가기 버튼 이벤트 핸들러
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        // 뒤로 가기 버튼 눌렀을 때 처리
        if(keyCode === KeyEvent.KEYCODE_BACK) {
            // 뒤로가기 버튼을 처음 눌렀거나 누른지 2초가 지났을 때 처리
            if(System.currentTimeMillis() - initTime > 2000) {
                Toast.makeText(this, "한번 더 누르면 종료 됩니다", Toast.LENGTH_SHORT).show()
                initTime = System.currentTimeMillis()
                return true
            }
        }
        return super.onKeyDown(keyCode, event)
    }
}

 

 

코드를 조금 해석하자면, 

멈춘 시각을 저장해주는 것이 중요하다고 느껴졌다!

타이머가 돌아가는 것을 생각해보면,
우선 시작버튼을 누르면 초가 1초, 2초 지날 것이다

그리고 멈춤 버튼을 누르면, 2초에서 멈출 것이고

다시 시작 버튼을 누르면 2초에서 3초, 4초가 될 것이다


그래서 멈춘 시각을 알려주는 pauseTime을 저장해두는 것이다
위의 예시를 들어서 보면, 2초를 pauseTime에 넘겨둔 다음, 재시작할 때 2를 더해주는 것이다. 그래서 처음엔 0으로 초기화를 해 두는 것이다

그리고 리셋버튼을 누르면 모든 것을 0으로 바꿔준다

 







추가로 isEnabled를 넣으면 시작을 눌렀을 때 현재 클릭한 버튼이 무엇인지 직관적으로 볼 수 있고, 사용할 수 있는 버튼이 무엇인지 알 수 있어서 효과적으로 느껴졌다.
앞으로 이 점을 유의해서 코드를 작성해야할 것 같다.



마지막으로 뒤로가기 버튼 이벤트 핸들러를 넣은 것도 굉장히 인상적이었다.

옛날에 자바를 배울 때, 교수님께서 항상 사용자 입장이 되어 최대한 사용하기 편한 코드를 작성하라고 하셨다. 즉, 어떠한 앱이나 서비스를 사용할 때도 X 버튼을 눌렀을 때, 정말 종료할 것인지 물어보는 것도 효과적인 방법이라고 배웠다!

뒤로가기 버튼을 눌렀을 때, 바로 꺼지는 것 보다 한번 더 누르면 종료된다는 토스트 메시지를 띄어주면 사용자가 더 편리하게 사용할 수 있을 것이다.

 

 

 

 


 

 

이건 정말정말 옛날에 타이머 만든 것의 일부!

 

심지어 findviewbyid로 코딩했었다

timer 와 runOnUiThread()를 사용해서 스톱워치 구현했다

버튼은 리셋 버튼과 시작/멈춤 버튼 두가지를 넣었다.

 

위의 코드가 훨씬 간결하니 위의 코드를 익히는 것이 좋을 것 같다 (이건 정말 내 생각 이다..!)

 

 start_button.setOnClickListener {
            isRunning = !isRunning
            if (isRunning) {
                timer = timer(period = 1000) {
                    time++

                    var sec = time % 60
                    var min = (time / 60) % 60
                    var hour = (time / 60) / 60

                    activity?.runOnUiThread {
                        myView.findViewById<TextView>(R.id.timer_sec).setText("$sec")
                        myView.findViewById<TextView>(R.id.timer_min).setText("$min")
                        myView.findViewById<TextView>(R.id.timer_hour).setText("$hour")
                    }
                }
            } else {
                timer?.cancel()
            }
        }
        restart_button.setOnClickListener {
            timer?.cancel()

            time = 0
            isRunning = false
            activity?.runOnUiThread {
                myView.findViewById<TextView>(R.id.timer_hour).setText("00")
                myView.findViewById<TextView>(R.id.timer_min).setText("00")
                myView.findViewById<TextView>(R.id.timer_sec).setText("00")
            }
        }
-

 

 

옛날에 코딩한 것 결과화면

 

 

 


 

 

위 글은 '깡쌤 토마토' 티스토리를 보고 공부한 뒤, 저만의 방법으로 해석하고 정리한 내용입니다.

 

728x90

댓글