Android ViewModel定时任务

Kotlin 复制代码
class MainModel : BaseViewModel() {

    // 持有定时任务的Job对象,用于后续取消任务
    private var timerJob: Job? = null

    // 定时任务结束的高阶函数回调(上层注册,ViewModel内部触发)
    var onTimerFinish: (() -> Unit)? = null

    /**
     * 启动定时任务
     * @param delaySeconds 延迟执行的秒数(N秒)
     */
    fun startTimerTask(delaySeconds: Long) {
        // 先取消已有任务,避免重复启动
        cancelTimerTask()
        // 基于viewModelScope启动协程,生命周期与ViewModel绑定
        timerJob = viewModelScope.launch {
            try {
                // 核心:延迟N秒执行(单位:毫秒)
                delay(delaySeconds * 1000)
                // 定时任务正常结束,触发回调通知上层
                onTimerFinish?.invoke()
            } catch (e: Exception) {
                // 协程被取消时会抛出CancellationException,此处捕获避免崩溃
                // 硬件错误/手动取消时,任务终止,不触发结束回调
                e.printStackTrace()
            }
        }
    }

    /**
     * 取消定时任务(硬件错误/手动终止时调用)
     */
    fun cancelTimerTask() {
        // 取消Job并置空,确保任务完全终止
        timerJob?.cancel()
        timerJob = null
    }

    /**
     * ViewModel销毁时自动调用,双重保障取消任务(防止内存泄漏)
     */
    override fun onCleared() {
        super.onCleared()
        cancelTimerTask()
        // 清空回调,避免上层页面已销毁仍持有引用
        onTimerFinish = null
    }

}

使用:

Kotlin 复制代码
class TimerTaskActivity : AppCompatActivity() {
    private lateinit var timerViewModel: TimerTaskViewModel
    private lateinit var btnStart: Button
    private lateinit var btnCancel: Button

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

        // 初始化ViewModel(ViewModelProvider确保生命周期独立于Activity)
        timerViewModel = ViewModelProvider(this)[TimerTaskViewModel::class.java]
        // 绑定控件
        btnStart = findViewById(R.id.btn_start_timer)
        btnCancel = findViewById(R.id.btn_cancel_timer)

        // 1. 点击开始:执行5秒定时任务(可自定义delaySeconds)
        btnStart.setOnClickListener {
            Toast.makeText(this, "定时任务启动,5秒后结束", Toast.LENGTH_SHORT).show()
            timerViewModel.startTimerTask(delaySeconds = 5)
        }

        // 2. 注册定时任务结束回调:执行后续业务逻辑
        timerViewModel.onTimerFinish = {
            runOnUiThread { // 确保回调在主线程执行(UI操作必须主线程)
                Toast.makeText(this, "定时任务结束!开始执行后续逻辑", Toast.LENGTH_LONG).show()
                // 此处写你的后续业务逻辑(如接口请求、UI更新、数据处理等)
                doSubsequentLogic()
            }
        }

        // 3. 硬件错误/手动取消:点击按钮终止任务(实际可在硬件错误回调中调用)
        btnCancel.setOnClickListener {
            timerViewModel.cancelTimerTask()
            Toast.makeText(this, "定时任务已取消", Toast.LENGTH_SHORT).show()
        }
    }

    /**
     * 定时任务结束后的后续逻辑示例
     */
    private fun doSubsequentLogic() {
        // 示例:更新UI、请求网络、操作数据库等
        btnStart.isEnabled = true
        // ... 你的业务代码
    }

    /**
     * 页面销毁时,ViewModel会自动调用onCleared()取消任务,无需额外处理
     * 若有硬件错误检测逻辑,可在对应的回调中调用 timerViewModel.cancelTimerTask()
     */
    // 示例:硬件错误检测回调(根据实际硬件SDK调整)
    private fun onHardwareErrorDetected() {
        timerViewModel.cancelTimerTask()
        Toast.makeText(this, "检测到硬件错误,已取消定时任务", Toast.LENGTH_SHORT).show()
    }
}
相关推荐
山河木马5 小时前
矩阵专题3-怎么创建投影矩阵(uProjectionMatrix)
javascript·webgl·计算机图形学
泯泷7 小时前
第 2 篇:设计第一套字节码:Opcode、Instruction 与 Constant Pool
前端·javascript·安全
泯泷7 小时前
第 1 篇:从 1 + 2 开始:亲手写出第一台 JSVM
前端·javascript·安全
朦胧之8 小时前
页面白屏卡住排查方法
前端·javascript
石山岭8 小时前
自己动手写了一个 Android 虚拟定位 App:GPSSimulate 技术实
android·前端
犇驫聊AI8 小时前
Chrome DevTools MCP + Claude Code 自定义skills生成接口代码生成器
前端·javascript
kyriewen9 小时前
别再这样写 async/await 了:我在 Code Review 中见过最多的 8 个错误
前端·javascript·面试
杉氧10 小时前
副作用 (Side Effects) 全攻略:如何像大师一样掌控 Composable 的生命周期?
android·架构·android jetpack
用户2986985301413 小时前
在 React 中使用 JavaScript 将 Excel 转换为 SVG
前端·javascript·react.js
labixiong14 小时前
手写Promise--微任务、静态方法、async/await 全搞懂(三)
前端·javascript