协程工具类

在日常开发中,协程已成为处理异步任务的核心工具,广泛应用于:

• 网络请求调用 - 替代传统回调,实现同步式编码风格

• 复杂数据运算 - 在后台线程执行密集型计算任务

• 数据流处理 - 通过Flow构建响应式数据流

• 数据库操作 - 高效管理本地数据的读写访问

• 多任务协作 - 优雅处理并发执行与依赖关系

Kotlin 复制代码
import android.os.Handler
import android.os.Looper
import androidx.annotation.Keep
import kotlinx.coroutines.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.coroutines.CoroutineContext

/**
 * 完整的UI线程工具类
 * 提供协程和Handler两种方式在主线程执行任务
 * 支持延迟执行、任务取消、生命周期管理等功能
 */
@Keep
object UIThreadUtils : CoroutineScope {

    // 主线程协程作用域
    private val mainScope = MainScope()
    
    // 主线程Handler
    private val mainHandler by lazy { Handler(Looper.getMainLooper()) }
    
    // 存储可取消的任务
    private val delayedTasks = ConcurrentHashMap<String, Runnable>()
    
    override val coroutineContext: CoroutineContext
        get() = mainScope.coroutineContext

    // region 协程方式
    
    /**
     * 在主线程执行协程任务
     * @param block 要执行的挂起函数块
     * @return Job对象,可用于取消任务
     */
    @Keep
    fun launchOnUI(block: suspend CoroutineScope.() -> Unit): Job {
        return mainScope.launch(Dispatchers.Main) {
            try {
                block()
            } catch (e: CancellationException) {
                // 协程取消是正常情况,不处理
                throw e
            } catch (e: Exception) {
                handleException(e)
            }
        }
    }
    
    /**
     * 在主线程执行协程任务并返回结果
     * @param block 要执行的挂起函数块
     * @return Deferred对象,可用于获取结果
     */
    @Keep
    fun <T> asyncOnUI(block: suspend CoroutineScope.() -> T): Deferred<T> {
        return mainScope.async(Dispatchers.Main) {
            try {
                block()
            } catch (e: CancellationException) {
                throw e
            } catch (e: Exception) {
                handleException(e)
                throw e
            }
        }
    }
    
    /**
     * 延迟执行协程任务
     * @param delayMillis 延迟时间(毫秒)
     * @param block 要执行的挂起函数块
     * @return Job对象,可用于取消任务
     */
    @Keep
    fun launchOnUIDelayed(delayMillis: Long, block: suspend CoroutineScope.() -> Unit): Job {
        return mainScope.launch(Dispatchers.Main) {
            try {
                delay(delayMillis)
                block()
            } catch (e: CancellationException) {
                throw e
            } catch (e: Exception) {
                handleException(e)
            }
        }
    }
    
    
    // region Handler方式
    
    /**
     * 在主线程执行任务(智能判断当前线程)
     * @param block 要执行的代码块
     */
    @Keep
    fun runOnUI(block: () -> Unit) {
        if (isOnMainThread()) {
            safeExecute(block)
        } else {
            mainHandler.post { safeExecute(block) }
        }
    }
    
    /**
     * 在主线程执行任务(强制切换到主线程)
     * @param block 要执行的代码块
     */
    @Keep
    fun postToUI(block: () -> Unit) {
        mainHandler.post { safeExecute(block) }
    }
    
    /**
     * 延迟执行任务
     * @param delayMillis 延迟时间(毫秒)
     * @param block 要执行的代码块
     * @return 任务标识符,可用于取消任务
     */
    @Keep
    fun runOnUIDelayed(delayMillis: Long, block: () -> Unit): String {
        val taskId = System.currentTimeMillis().toString() + "_" + block.hashCode()
        val runnable = Runnable { safeExecute(block) }
        
        delayedTasks[taskId] = runnable
        mainHandler.postDelayed({
            delayedTasks.remove(taskId)
            safeExecute(block)
        }, delayMillis)
        
        return taskId
    }
    
    /**
     * 延迟执行任务(带标签,便于管理)
     * @param delayMillis 延迟时间(毫秒)
     * @param tag 任务标签
     * @param block 要执行的代码块
     * @return 任务标识符
     */
    @Keep
    fun runOnUIDelayed(delayMillis: Long, tag: String, block: () -> Unit): String {
        val taskId = "${tag}_${System.currentTimeMillis()}"
        val runnable = Runnable { safeExecute(block) }
        
        delayedTasks[taskId] = runnable
        mainHandler.postDelayed({
            delayedTasks.remove(taskId)
            safeExecute(block)
        }, delayMillis)
        
        return taskId
    }
    
    /**
     * 取消延迟任务
     * @param taskId 任务标识符
     */
    @Keep
    fun cancelDelayedTask(taskId: String) {
        val runnable = delayedTasks[taskId]
        runnable?.let {
            mainHandler.removeCallbacks(it)
            delayedTasks.remove(taskId)
        }
    }
    
    /**
     * 取消指定标签的所有任务
     * @param tag 任务标签
     */
    @Keep
    fun cancelDelayedTasksByTag(tag: String) {
        val tasksToRemove = delayedTasks.keys.filter { it.startsWith("${tag}_") }
        tasksToRemove.forEach { taskId ->
            val runnable = delayedTasks[taskId]
            runnable?.let {
                mainHandler.removeCallbacks(it)
                delayedTasks.remove(taskId)
            }
        }
    }
    
    /**
     * 取消所有延迟任务
     */
    @Keep
    fun cancelAllDelayedTasks() {
        delayedTasks.values.forEach { mainHandler.removeCallbacks(it) }
        delayedTasks.clear()
    }
    
    // endregion
    
    // region 工具方法
    
    /**
     * 判断当前是否在主线程
     */
    @Keep
    fun isOnMainThread(): Boolean {
        return Looper.getMainLooper() == Looper.myLooper()
    }
    
    /**
     * 确保在主线程执行,如果不在主线程则抛出异常
     */
    @Keep
    fun checkMainThread() {
        if (!isOnMainThread()) {
            throw IllegalStateException("This operation must be run on UI thread. Current thread: ${Thread.currentThread().name}")
        }
    }
    
    /**
     * 安全执行代码块,捕获异常
     */
    private fun safeExecute(block: () -> Unit) {
        try {
            block()
        } catch (e: Exception) {
            handleException(e)
        }
    }
    
    /**
     * 异常处理
     */
    private fun handleException(e: Exception) {
        // 这里可以自定义异常处理逻辑,比如日志记录、崩溃上报等
        e.printStackTrace()
        
        // 示例:简单的日志输出
        println("UIThreadUtils Exception: ${e.message}")
        
        // 在实际项目中,你可以使用自己的日志系统
        // Logger.e("UIThreadUtils", "Execute task error", e)
    }
    
    /**
     * 清理资源
     */
    @Keep
    fun destroy() {
        cancelAllDelayedTasks()
        mainScope.cancel()
    }
    
    // endregion
}

// region 扩展函数

/**
 * 在UI线程执行协程任务的扩展函数
 */
@Keep
fun CoroutineScope.launchOnUI(block: suspend CoroutineScope.() -> Unit): Job {
    return UIThreadUtils.launchOnUI(block)
}

/**
 * 在UI线程执行任务的扩展函数
 */
@Keep
fun (() -> Unit).runOnUI() {
    UIThreadUtils.runOnUI(this)
}

/**
 * 延迟执行的扩展函数
 */
@Keep
fun (() -> Unit).runOnUIDelayed(delayMillis: Long): String {
    return UIThreadUtils.runOnUIDelayed(delayMillis, this)
}

使用的方式:

Kotlin 复制代码
// 1. 协程方式
// 基本使用
UIThreadUtils.launchOnUI {
    textView.text = "更新UI"
    // 可以调用挂起函数
    val result = withContext(Dispatchers.IO) { fetchData() }
    updateUI(result)
}

// 获取结果
val deferred = UIThreadUtils.asyncOnUI {
    processData()
}
// 在其他地方获取结果
launch {
    val result = deferred.await()
}

// 延迟执行
UIThreadUtils.launchOnUIDelayed(1000) {
    showToast("延迟显示")
}

// 2. Handler方式
// 智能判断线程
UIThreadUtils.runOnUI {
    updateView()
}

// 强制切换到主线程
UIThreadUtils.postToUI {
    refreshUI()
}

// 延迟执行(可取消)
val taskId = UIThreadUtils.runOnUIDelayed(2000, "refresh_task") {
    refreshData()
}

// 取消任务
UIThreadUtils.cancelDelayedTask(taskId)

// 3. 扩展函数方式
{ updateUI() }.runOnUI()

{ showDialog() }.runOnUIDelayed(500)

coroutineScope.launchOnUI {
    // 在协程作用域中直接使用
}

特点:

  1. 双重支持:同时提供协程和Handler两种方式

  2. 线程安全:智能判断当前线程,避免不必要的线程切换

  3. 任务管理:支持延迟任务的取消和管理

  4. 异常处理:统一的异常处理机制

  5. 生命周期感知:提供destroy方法清理资源

  6. 扩展函数:提供更简洁的调用方式

  7. 性能优化:避免内存泄漏,合理管理资源

相关推荐
阿兰哥6 小时前
【调试篇5】TransactionTooLargeException 原理解析
android·性能优化·源码
爱吃水蜜桃的奥特曼7 小时前
玩Android Flutter版本,通过项目了解Flutter项目快速搭建开发
android·flutter
太过平凡的小蚂蚁7 小时前
Android 版本特性完全解析:从6.0到16.0的实用指南
android
杨筱毅7 小时前
【底层机制】【Android】深入理解UI体系与绘制机制
android·底层机制
介一安全8 小时前
【Frida Android】基础篇8:Java层Hook基础——调用带对象参数的方法
android·网络安全·逆向·安全性测试·frida
puyaCheer8 小时前
Android 13 启动的时候会显示一下logo,很不友好
android·gitee
豆豆豆大王8 小时前
Android的Activity与intent知识点
android studio
long_hai_d9 小时前
Aosp14桌面壁纸和锁屏壁纸的设置和加载分析
android
2501_9160074710 小时前
iOS 26 软件性能测试 新版系统下评估全流程 + 多工具辅助方案
android·macos·ios·小程序·uni-app·cocoa·iphone