ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kotlin] 스톱워치: thread (runOnUiThread), Deprecated, SDK 버전
    공부 기록/Kotlin 2022. 3. 26. 15:21
    728x90

    Joyce의 안드로이드 앱 프로그래밍 with 코틀린

    07 project 스톱워치: 스레드


    플러터로 프로젝트를 만들다가 잘 안되는데 이유는 모르겠고, Android의 개념을 제대로 이해하지 못해서 이유를 못 찾는 듯 싶어 다시 코틀린부터 시작해보기로 했다. 개념은 한번 다시 훑고, 클론 코딩을 통해 실습을 시작하였다.

    첫번 째, 프로젝트는 스탑워치 만들기. 2년 전보다 훨씬 친숙하고 수월해졌다. 


    MainActivity 클래스는 AppCompatActivity 클래스를 상속받고, AppCompatActivity 클래스는 Activity 클래스를 상속받는다. AppCompatActivity는 오래된 안드로이드 버전과 호환성을 유지하고 새로운 기능이 추가된 액티비티 클래스이다. (added after Android studio 1.5)

    onCreate()는 클래스가 생성될 때 맨 처음에 호출되는 콜백 함수로 여기에 초기화 코드 넣으면 됨. 매개변수인 savedInstanceState: Bundle?은 특정 상황에서 액티비티가 저장한 값을 불러오는 값. 


    Deprecated vs Delete

    디프리케이트 API: 아직까지 사용은 할 수 있지만 조만간 사라질 수 있다고 예고된 API (p. 225)

    네이버 사전에 따르면,

    (신조어) 중요도가 떨어져 더 이상 사용되지 않고 앞으로는 사라지게 될 (컴퓨터 시스템 기능 등)

    삭제(Delete)와 디프레키에트(Deprecated)는 다르다. 사용은 할 수 있지만 앞으로 지원되지 않을 기능을 디프리케이트로 보는 것이 맞겠다. 


     

    모듈 레벨의 build.gradle에서 프로젝트의 모든 SDK 버전을 확인할 수 있다. 

    • compileSdk: Gradle에 어떤 안드로이드 SDK 버전으로 앱을 컴파일할지 지정. 런타임에는 영향 없음.
    • minSDk: 앱을 사용할 수 있는 최소한의 API 레벨. 앱을 설치하려는 기기의 API 레벨이 minSdk 버전보다 낮으면 설치되지 않음.
    • targetSdk: 앱이 기기에서 동작할 때 사용하는 SDK 버전기기버전이 API 28d이고 targetSdk가 API 24이면 앱은 24를 기본으로 동작. 구글에서는 앱 개발 당시의 최신 API를 targetSdk로 지정할 것을 권장. 

    완성 결과. (에뮬레이션 대신 휴대폰 연결해서 개발자 모드에서 런)

    완성 코드.

    package com.example.stopwatch
    
    import android.os.Bundle
    import com.google.android.material.snackbar.Snackbar
    import androidx.appcompat.app.AppCompatActivity
    import androidx.navigation.findNavController
    import androidx.navigation.ui.AppBarConfiguration
    import androidx.navigation.ui.navigateUp
    import androidx.navigation.ui.setupActionBarWithNavController
    import android.view.Menu
    import android.view.MenuItem
    import android.view.View
    import android.widget.Button
    import com.example.stopwatch.databinding.ActivityMainBinding
    import kotlin.concurrent.timer
    import java.util.*
    import android.widget.TextView
    
    class MainActivity : AppCompatActivity(), View.OnClickListener { // 클릭이벤트 처리 인터페이스 추가
    
        var isRunning = false // 실행확인용 변수
        var timer : Timer? = null
        var time = 0
    
        private lateinit var btn_start: Button
        private lateinit var btn_refresh: Button
        private lateinit var tv_millisecond: TextView
        private lateinit var tv_second: TextView
        private lateinit var tv_minute: TextView
    
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                setContentView(R.layout.activity_main) // 메인 레이아웃을 뷰에 보이도록 하기
    
                //xml 레이아웃 파일에서 정의한 뷰들을 액티비에서 사용할 수 있도 가져와 변수에 저장.
                btn_start = findViewById(R.id.btn_start)
                btn_refresh = findViewById(R.id.btn_refresh)
                tv_millisecond = findViewById(R.id.tv_millisecond)
                tv_second = findViewById(R.id.tv_second)
                tv_minute = findViewById(R.id.tv_minute)
    
                // 버튼별 onClickListener 등록. setOnClickListener() 메서드를 이용해 onClickListener를 추가해주어야 클릭이 가능해짐.
                btn_start.setOnClickListener(this)
                btn_refresh.setOnClickListener(this)
    
            }
    
            override fun onClick(v: View?) { // 클릭이벤트가 발생했을때 뷰 ID가 x면 y 함수 실행하는 로직.
                when(v?.id){
                    R.id.btn_start -> {
                        if(isRunning) {
                            pause()
                        } else {
                            start()
                        }
                    }
                    R.id.btn_refresh -> {
                        refresh()
                    }
                }
            }
    
            private fun start() { // 이 함수가 실행되면 다음과 같이 텍스트, 배경, 동작상태 값 변경됨.
                btn_start.text = "일시정지"
                btn_start.setBackgroundColor(getColor(R.color.red))
                isRunning = true
    
                timer = timer(period = 10) {
                    // 코틀린에서 제공하는 timer 함수로 일정한 주기로 반복하는 동작을 수행할 때 사용됨. 10밀리초 단위로 시간을 증가시키도록 작성. 10밀리초 단위의 타이머 동작.
                    time++
    
                    //시간 계산
                    val milli_second = time % 100
                    val second = (time % 6000) / 100
                    val minute = time % 6000
    
                    runOnUiThread{ //아래  텍스트뷰를 수정하는 블록에 runOnUiThread를 사용해서 감쌈. UI 작업이 백그라운드 스레드가 아닌 UI 스레드(메인 스레드)에서 일어남.
                        // runOnUiThread로 감싸지 않으면 백그라운드 스레드에서 실행되어 다음과 같은 에러 생성:
                        // android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
                        if (isRunning) // UI update 조건. isRunning이 true일 경우에만 UI가 업데이트.
    
                        // 분, 초, 밀리초 텍스튜부를 0.01초마다 갱신. (시간이 한자리일때 전체 텍스트 길이를 두 자리로 유지하기 위함)
                            tv_millisecond.text = if(milli_second < 10) ".0${milli_second}" else ".{$milli_second}"
                            tv_second.text = if(second < 10) ":0${second}" else ":{$second}"
                            tv_minute.text = "${minute}"
                    }
    
    
                }
            }
            private fun pause() {
                btn_start.text="시작"
                btn_start.setBackgroundColor(getColor(R.color.bright_purple))
    
                isRunning = false
                timer?.cancel() // 타이머 멈추기.
            }
            private fun refresh() {
                timer?.cancel()
    
                btn_start.text="시작"
                btn_start.setBackgroundColor(getColor(R.color.bright_purple))
                isRunning = false
    
                time = 0
                tv_millisecond.text =".00"
                tv_second.text = ":00"
                tv_minute.text = "00"
            }
    }

     

    댓글

Designed by Tistory.