kotlin 코드 에러 및 수정

sun·2024년 9월 18일
0

Android

목록 보기
2/2
package com.example.myhobby

import android.os.Bundle
import android.widget.TextView
import android.widget.Button
import androidx.activity.ComponentActivity
import java.util.Timer
import kotlin.concurrent.timer
import kotlin.math.abs // abs 함수 임포트 필요
import java.util.*

class MainActivity : ComponentActivity() {
    var p_num = 3
    var k = 1

    fun main() {

        var stage = 1
        var sec = 0
        var timerTask: Timer? = null
        val tv: TextView = findViewById(R.id.textView)
        val timer: TextView = findViewById(R.id.timer)
        val text_p: TextView = findViewById(R.id.text_p)
        val btn: Button = findViewById(R.id.button_id)
        val random_box = Random()
        val num = random_box.nextInt(1001)

        timer.text = ((num.toFloat()) / 100).toString()
        btn.text = getString(R.string.start)  // "Start" 문자열을 리소스에서 가져옴

        btn.setOnClickListener {
            stage++
            if (stage == 2) {
                // 타이머 시작
                timerTask = timer(period = 10) {
                    sec++
                    runOnUiThread {
                        tv.text = (sec.toFloat() / 100).toString()
                    }
                }
                btn.text = getString(R.string.stop)
            } else if (stage == 3) {
                // 타이머 중지
                timerTask?.cancel()
                val point = abs(sec - num).toFloat() / 100
                text_p.text = point.toString()
                btn.text = getString(R.string.restart)
                stage = 0
            } else if (stage == 1) {
                if (k < p_num) {
                    k++
                    main()
                } else {
                    println(k)
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)  // onCreate 안에서 호출
    }
}
  1. main() 함수 호출 문제
    main() 함수는 일반적으로 ComponentActivity에서 메인 함수로 쓰이는 것이 아니라, 앱의 진입점은 onCreate() 메서드입니다. 하지만 현재 코드는 main() 함수를 UI 이벤트 안에서 호출하고 있습니다.
    또한, main() 함수는 명시적으로 호출되는 것이 아니라, 앱이 실행되면 onCreate() 메서드 내에서 필요한 초기화 작업을 수행해야 합니다.
  2. setOnClickListener의 단계 변화 로직
    stage 변수를 통해 버튼의 상태를 관리하고 있는데, stage가 3이 될 때 0으로 초기화하지 않아서 버튼을 계속 눌렀을 때 동작이 의도대로 되지 않을 수 있습니다.
  3. runOnUiThread 문제
    UI 갱신은 onCreate에서 초기화한 뷰와 함께 이루어져야 하지만, 코드에서 UI 요소가 초기화되지 않았거나 제대로 연결되지 않은 상태로 동작할 수 있습니다.
  4. main() 함수 내에서 재귀 호출 문제
    main() 함수 내에서 main()을 재귀 호출하고 있습니다. 이 방식은 불필요한 재귀를 만들고, 메모리 부족 또는 스택 오버플로우를 초래할 수 있습니다.
  5. findViewById 위치
    findViewById는 뷰가 이미 setContentView로 설정된 이후에 호출해야 합니다. 즉, 뷰는 onCreate 내에서 초기화되어야 합니다.
    해결 방법
    main() 함수의 호출 방식을 수정하고, 버튼 클릭 이벤트를 onCreate() 내에서 처리하도록 구조를 변경합니다.
    stage 상태 관리를 조금 더 명확하게 하고, 재귀 호출을 피합니다.
    UI 요소 초기화를 onCreate()에서 수행합니다.
package com.example.myhobby

import android.os.Bundle
import android.widget.TextView
import android.widget.Button
import androidx.activity.ComponentActivity
import java.util.Timer
import kotlin.concurrent.timer
import kotlin.math.abs
import java.util.*

class MainActivity : ComponentActivity() {
    var p_num = 3
    var k = 1
    var stage = 1
    var sec = 0
    var timerTask: Timer? = null

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

        // 뷰 초기화
        val tv: TextView = findViewById(R.id.textView)
        val timer: TextView = findViewById(R.id.timer)
        val text_p: TextView = findViewById(R.id.text_p)
        val btn: Button = findViewById(R.id.button_id)

        // 랜덤 숫자 생성
        val random_box = Random()
        val num = random_box.nextInt(1001)
        timer.text = ((num.toFloat()) / 100).toString()

        // 버튼의 초기 텍스트 설정
        btn.text = getString(R.string.start)

        btn.setOnClickListener {
            stage++
            when (stage) {
                2 -> {
                    // 타이머 시작
                    timerTask = timer(period = 10) {
                        sec++
                        runOnUiThread {
                            tv.text = (sec.toFloat() / 100).toString()
                        }
                    }
                    btn.text = getString(R.string.stop)
                }
                3 -> {
                    // 타이머 중지 및 포인트 계산
                    timerTask?.cancel()
                    val point = abs(sec - num).toFloat() / 100
                    text_p.text = point.toString()
                    btn.text = getString(R.string.restart)
                }
                4 -> {
                    // 게임 재시작
                    if (k < p_num) {
                        k++
                        resetGame()
                    } else {
                        println("게임 종료: $k 라운드 완료")
                    }
                    stage = 1  // 다시 시작할 수 있도록 stage를 초기화
                    btn.text = getString(R.string.start)
                }
            }
        }
    }

    // 게임을 리셋하는 함수
    private fun resetGame() {
        sec = 0
        timerTask = null
        // 추가적인 게임 리셋 로직이 필요하면 여기에 추가
    }
}

주요 수정 사항:
main() 함수 제거: main() 함수를 제거하고 모든 로직을 onCreate() 안에 배치했습니다. resetGame() 메서드를 통해 재시작 로직을 처리하도록 했습니다.
버튼 클릭 이벤트 개선: 버튼 클릭 이벤트에서 stage 값을 관리하여 게임 상태를 처리하고, 재귀 호출을 제거했습니다.
UI 요소 초기화: TextView, Button 등의 UI 요소는 onCreate()에서 초기화되며, 뷰가 설정된 이후 호출되도록 변경했습니다.
이제 이 코드는 실행될 때 정상적으로 동작할 가능성이 큽니다. 추가적으로, Random을 활용한 로직이나 타이머가 예상대로 작동하는지도 테스트해 보세요.

0개의 댓글