为什么你现在就需要它
\n想象一下:你正在编写一个应用程序,需要在用户点击按钮 5 秒后显示一个通知。或者,仅在用户输入完毕 2 秒后才执行对服务器的请求。又或者,只是想制作一个带有延迟的漂亮动画。如果不懂如何在 Kotlin 中延迟调用函数,你将寸步难行。
\n这个问题是 Stack Overflow 上最热门的问题之一(成千上万的浏览量!),这并非没有道理。在 Kotlin 中,有 多达 4 种方法 可以实现延迟调用,每种方法都适用于不同的场景。在本文中,我们将逐一介绍它们:从协程中简单的 delay() 到 Android 中经典的 Handler。你将了解应该选择哪种方法及其原因,最重要的是,你将看到可以直接复制到项目中的可运行代码。
方法 1:协程与 delay()(现代且推荐)
\n这是现代 Kotlin 中最优雅且推荐的方法。协程是轻量级线程,不会阻塞主线程。delay() 方法会在指定时间内暂停协程,然后恢复它。
要使用协程,你需要在 build.gradle.kts 中添加依赖:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")\n代码实现如下:
\nimport kotlinx.coroutines.*\n\nfun main() = runBlocking {\n println("开始:${System.currentTimeMillis()}")\n\n // 启动一个带延迟的协程\n launch {\n delay(3000L) // 等待 3 秒\n println("3 秒已过:${System.currentTimeMillis()}")\n myDelayedFunction() // 调用目标函数\n }\n\n println("正在等待...(此行会立即执行)")\n}\n\nfun myDelayedFunction() {\n println("函数已执行!")\n}\n重要提示: delay() 是一个 挂起 函数(suspend function)。它只能在协程内部或其他挂起函数中调用。如果你尝试在协程外部调用 delay(),编译器会报错。
如何在 Android 中使用协程进行延迟调用
\n在 Android 开发中,协程是事实上的标准。以下是 Activity 的示例:
\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\nimport kotlinx.coroutines.*\n\nclass MainActivity : AppCompatActivity() {\n\n private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n setContentView(R.layout.activity_main)\n\n // 2 秒后显示 Toast\n scope.launch {\n delay(2000L)\n showToast("2 秒已过!")\n }\n }\n\n private fun showToast(message: String) {\n android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show()\n }\n\n override fun onDestroy() {\n super.onDestroy()\n scope.cancel() // 在 Activity 销毁时取消所有任务\n }\n}\n请注意:我们使用 Dispatchers.Main 来处理 UI。并且务必在 onDestroy() 中取消 scope,以避免内存泄漏。
方法 2:Handler 与 postDelayed()(Android 经典方法)
\n如果你正在编写 Android 应用,并且不想(或不能)使用协程,那么经典的 Handler 仍然有效。这种方法在协程时代之前非常流行。
import android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport androidx.appcompat.app.AppCompatActivity\n\nclass MainActivity : AppCompatActivity() {\n\n private val handler = Handler(Looper.getMainLooper())\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n setContentView(R.layout.activity_main)