Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ android {
}

dependencies {
//coroutine
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2")

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/java/com/example/bcsd_android_2025_1/LapAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.example.bcsd_android_2025_1

import LapData
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class LapAdapter(private val lapList: List<LapData>) :
RecyclerView.Adapter<LapAdapter.LapViewHolder>() {

class LapViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val number: TextView = view.findViewById(R.id.lap_text_number)
val section: TextView = view.findViewById(R.id.lap_text_sectionRecord)
val total: TextView = view.findViewById(R.id.lap_text_totalTime)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LapViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.lap_list, parent, false)
return LapViewHolder(view)
}

override fun onBindViewHolder(holder: LapViewHolder, position: Int) {
val lap = lapList[position]
holder.number.text = lap.number.toString()
holder.section.text = lap.sectionTime
holder.total.text = lap.totalTime
}

override fun getItemCount() = lapList.size
}
5 changes: 5 additions & 0 deletions app/src/main/java/com/example/bcsd_android_2025_1/LapData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data class LapData(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사소한 점이긴 한데, package name이 누락되어 있네요

val number: Int,
val sectionTime: String,
val totalTime: String
)
111 changes: 108 additions & 3 deletions app/src/main/java/com/example/bcsd_android_2025_1/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,119 @@
package com.example.bcsd_android_2025_1

import LapData
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import android.os.SystemClock
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

private lateinit var timerText: TextView
private lateinit var startButton: Button
private lateinit var stopButton: Button
private lateinit var lapButton: Button
private lateinit var lapRecyclerView: RecyclerView
private lateinit var lapAdapter: LapAdapter
private val lapList = mutableListOf<LapData>()

private var isRunning = false
private var startTime = 0L // 시작시간
private var beforeTime = 0L // 누적시간
private var timerJob: Job? = null // 중단 위함
private var lastLapTime = 0L // 마지막 기록된 시간

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

timerText = findViewById(R.id.main_text_timer)
startButton = findViewById(R.id.main_button_start)
stopButton = findViewById(R.id.main_button_stop)
lapButton = findViewById(R.id.main_button_lap)
lapRecyclerView = findViewById(R.id.main_recycler_lap)

lapAdapter = LapAdapter(lapList)
lapRecyclerView.adapter = lapAdapter
lapRecyclerView.layoutManager = LinearLayoutManager(this)

startButton.setOnClickListener {
if (!isRunning) {
startTimer()
} else {
pauseTimer()
}
}

stopButton.setOnClickListener {
stopTimer()
}

lapButton.setOnClickListener {
if (!isRunning) return@setOnClickListener
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 처리 좋습니다


val now = SystemClock.elapsedRealtime()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오오... SystemClock.elapsedRealtime()를 사용하셨군요 좋습니다!
System.currentTimeMillis()와의 차이점도 알아보시면 좋을 것 같네요

val total = now - startTime + beforeTime
val section = if (lapList.isEmpty()) total else total - lastLapTime
lastLapTime = total

val lap = LapData(
number = lapList.size + 1,
sectionTime = formatTime(section),
totalTime = formatTime(total)
)

lapList.add(0, lap)
lapAdapter.notifyItemInserted(0)
lapRecyclerView.scrollToPosition(0)
}
}

private fun startTimer() {
isRunning = true
startButton.text = getString(R.string.main_pause)
startTime = SystemClock.elapsedRealtime() // 시작시점

timerJob = lifecycleScope.launch {
while (isRunning) {
val now = SystemClock.elapsedRealtime()
val totalTime = now - startTime + beforeTime // 총 누적 시간 = 현재 시간 - 시작시간 + 이전누적시간
timerText.text = formatTime(totalTime)
delay(10) // 10ms마다 갱신
}
}
}

private fun pauseTimer() {
isRunning = false
beforeTime += SystemClock.elapsedRealtime() - startTime // 이전 누적 시간에 이번에 흐른 시간 더함.
timerJob?.cancel()
startButton.text = getString(R.string.main_start)
}

private fun formatTime(ms: Long): String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long의 확장함수로 작성하면 더 좋을 것 같습니다

val minutes = ms / 1000 / 60
val seconds = (ms / 1000) % 60
val millis = (ms % 1000) / 10
return String.format("%02d : %02d : %02d", minutes, seconds, millis)
}

private fun stopTimer() {
isRunning = false
timerJob?.cancel() // 코루틴 정지 + 기록 초기화
startTime = 0L
beforeTime = 0L
lastLapTime = 0L
timerText.text = getString(R.string.main_default_time)
startButton.text = getString(R.string.main_start)

lapList.clear()
lapAdapter.notifyDataSetChanged()
}
}
95 changes: 93 additions & 2 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,103 @@
tools:context=".MainActivity">

<TextView
android:id="@+id/main_text_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Android!"
android:text="@string/main_default_time"
android:textSize="36sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.25" />

<Button
android:id="@+id/main_button_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_start"
android:layout_marginStart="50dp"
app:layout_constraintEnd_toStartOf="@id/main_button_stop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.40"/>

<Button
android:id="@+id/main_button_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_stop"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/main_button_start"
app:layout_constraintEnd_toStartOf="@id/main_button_lap"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.40"/>

<Button
android:id="@+id/main_button_lap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_lap"
android:layout_marginEnd="50dp"
app:layout_constraintStart_toEndOf="@id/main_button_stop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.40"/>

<TextView
android:id="@+id/main_text_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_number"
android:textSize="15sp"
android:layout_marginStart="50dp"
app:layout_constraintEnd_toStartOf="@id/main_text_sectionRecord"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="0.50" />

<TextView
android:id="@+id/main_text_sectionRecord"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_section_record"
android:textSize="15sp"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/main_text_number"
app:layout_constraintEnd_toStartOf="@id/main_text_totalTime"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.50" />

<TextView
android:id="@+id/main_text_totalTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/main_total_time"
android:textSize="15sp"
android:layout_marginEnd="50dp"
app:layout_constraintStart_toEndOf="@id/main_text_sectionRecord"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.50" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_recycler_lap"
android:layout_width="0dp"
android:layout_height="0dp"
android:padding="16dp"
app:layout_constraintTop_toBottomOf="@id/main_text_number"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>
47 changes: 47 additions & 0 deletions app/src/main/res/layout/lap_list.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/lap_list"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/lap_text_number"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/main_default_number"
android:textAlignment="center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/lap_text_sectionRecord"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.55"
app:layout_constraintHorizontal_weight="1" />

<TextView
android:id="@+id/lap_text_sectionRecord"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/main_default_time"
android:textAlignment="center"
app:layout_constraintStart_toEndOf="@id/lap_text_number"
app:layout_constraintEnd_toStartOf="@id/lap_text_totalTime"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.55"
app:layout_constraintHorizontal_weight="1" />

<TextView
android:id="@+id/lap_text_totalTime"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/main_default_time"
android:textAlignment="center"
app:layout_constraintStart_toEndOf="@id/lap_text_sectionRecord"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.55"
app:layout_constraintHorizontal_weight="1" />

</androidx.constraintlayout.widget.ConstraintLayout>
9 changes: 9 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
<resources>
<string name="app_name">BCSD_Android_2025-1</string>
<string name="main_default_time">00:00:00</string>
<string name="main_start">Start</string>
<string name="main_pause">Pause</string>
<string name="main_stop">Stop</string>
<string name="main_lap">Lap</string>
<string name="main_number">Number</string>
<string name="main_section_record">Section record</string>
<string name="main_total_time">Total time</string>
<string name="main_default_number">1</string>
</resources>