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()
    }
}
相关推荐
大白要努力!1 天前
Android图片预览功能实战:从需求到上线的完整方案
android·viewpager·图片预览·实战记录·photoview
Ljwuhe1 天前
类与对象(中)——运算符重载
开发语言·c++
郝学胜-神的一滴1 天前
深入理解链表:从基础到实践
开发语言·数据结构·c++·算法·链表·架构
敲敲了个代码1 天前
vue文件自动生成路由会成为主流
开发语言·前端·javascript·vue.js·前端框架
程序员林北北1 天前
【前端进阶之旅】typescriot的数据类型讲解(二)
前端·javascript·vue.js·react.js·typescript
你住过的屋檐1 天前
【Java】虚拟线程详解
java·开发语言
霍理迪1 天前
JS—事件高级
开发语言·javascript·ecmascript
范特西.i1 天前
QT聊天项目(8)
开发语言·qt
烟花落o1 天前
栈和队列的知识点及代码
开发语言·数据结构·笔记·栈和队列·编程学习
接着奏乐接着舞1 天前
vue3面试题
前端·javascript·vue.js