如何使用Kotlin实现Minute:Seconds:MILLISECONDS格式倒计时并支持macroseconds显示
Kotlin Countdown: MM:SS:mmm Format with Fast-Ticking Millisecond Display
Key Features Covered
- Proper
Minute:Seconds:Millisecondsformatting - Rapid millisecond updates (simulating microsecond-level ticking)
- Clean, cancelable timer logic using Coroutines (no messy Handlers!)
- Reusable code structure
Complete Implementation
First, let's create a reusable countdown manager (you can drop this into your project as a top-level class or inside your Activity/Fragment):
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch class CountdownManager { private var countdownJob: Job? = null /** * Starts a countdown * @param totalSeconds Total duration of the countdown in seconds * @param onTick Called every 10ms with the formatted time string * @param onFinish Called when the countdown reaches zero */ fun start(totalSeconds: Int, onTick: (String) -> Unit, onFinish: () -> Unit) { // Cancel any existing countdown to avoid duplicates countdownJob?.cancel() countdownJob = CoroutineScope(Dispatchers.Main).launch { var remainingMillis = totalSeconds * 1000L while (remainingMillis > 0) { onTick(formatTime(remainingMillis)) // Delay 10ms instead of 1s to get that fast-ticking millisecond effect // This updates the display 100 times per second, making the millis jump rapidly delay(10) remainingMillis -= 10 } // Final tick to show zero onTick(formatTime(0)) onFinish() } } /** * Stops the current countdown if it's running */ fun stop() { countdownJob?.cancel() } /** * Formats remaining milliseconds into MM:SS:mmm format * For the "10:59:(9,8,7..." effect, uncomment the alternative millis line below */ private fun formatTime(remainingMillis: Long): String { val minutes = (remainingMillis / 1000 / 60).toString().padStart(2, '0') val seconds = (remainingMillis / 1000 % 60).toString().padStart(2, '0') // Full millisecond display (e.g., 10:59:999) val millis = (remainingMillis % 1000).toString().padStart(3, '0') // Alternative: Only show last digit of millis for the rapid jump effect (e.g., 10:59:9) // val millis = (remainingMillis % 10).toString() return "$minutes:$seconds:$millis" } }
How to Use It (Android Example)
Integrate this into your Activity or Fragment easily:
import android.os.Bundle import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity() { private val countdownManager = CountdownManager() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val countdownText = findViewById<TextView>(R.id.countdown_text) // Start a 11-minute countdown (660 seconds = 10m59s) countdownManager.start( totalSeconds = 660, onTick = { formattedTime -> countdownText.text = formattedTime }, onFinish = { Toast.makeText(this, "Countdown done!", Toast.LENGTH_SHORT).show() } ) } // Always clean up the countdown to prevent memory leaks override fun onDestroy() { super.onDestroy() countdownManager.stop() } }
Why This Works
- Coroutines: We use
CoroutineScopeinstead ofHandlerbecause it's safer (auto-cancels with lifecycle if you useviewLifecycleOwnerin Fragments) and more readable. - 10ms Delay: By updating every 10ms instead of 1 second, the millisecond portion ticks rapidly—exactly the "9,8,7..." effect you're looking for.
- Flexible Formatting: The
formatTimefunction lets you switch between full millisecond display or just the last digit, depending on your UI needs.
Adaptation for Non-Android Kotlin
If you're using this in a plain Kotlin/JVM project, just adjust the CoroutineScope to use a background dispatcher (like Dispatchers.Default) and update your output method (e.g., print to console instead of updating a TextView):
// Example for Kotlin/JVM fun main() { val manager = CountdownManager() manager.start( totalSeconds = 10, onTick = { println(it) }, onFinish = { println("Countdown completed!") } ) // Keep the program running (you'd handle this differently in production) Thread.sleep(11000) manager.stop() }
内容的提问来源于stack exchange,提问作者as lan
相关产品推荐
相关产品推荐

