Android开发:基于 Kotlin 协程的设备指令控制工具类设计与实现

在安卓开发中,设备控制是一个常见的需求。本文将介绍如何使用 Kotlin 协程实现一个高效、健壮的设备指令控制工具类。该工具类支持指令队列、重试机制、状态管理等功能,并适配安卓平台,确保生命周期管理和主线程安全性。通过本文,你将学习到如何设计一个可扩展的工具类,并将其集成到安卓项目中。

库引入

build.gradle 文件中添加以下依赖:

gradle 复制代码
dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0" // Kotlin 协程
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0" // 安卓协程支持
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1" // ViewModel 支持
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1" // Lifecycle 支持
}

完整代码

1. 工具类代码
kotlin 复制代码
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow

/**
 * 指令发送工具类(适配安卓平台)
 *
 * @param sendCommand 发送指令的函数,返回指令是否成功
 * @param config 工具类配置
 */
class CommandSender(
    private val sendCommand: suspend (Command) -> Response,
    private val config: CommandSenderConfig = CommandSenderConfig()
) {
    // 指令队列
    private val commandChannel = Channel<Command>(capacity = Channel.UNLIMITED)

    // 指令状态流
    private val _commandStateFlow = MutableSharedFlow<CommandState>(replay = 1)
    val commandStateFlow = _commandStateFlow.asSharedFlow()

    // 协程作用域(使用 SupervisorJob)
    private val scope = CoroutineScope(config.dispatcher + SupervisorJob())

    // 是否正在运行
    private var isRunning = true

    init {
        // 启动指令处理协程
        scope.launch {
            for (command in commandChannel) {
                if (!isRunning) break // 如果工具类已关闭,停止处理
                sendCommandWithRetry(command)
            }
        }
    }

    /**
     * 添加指令到队列
     */
    fun addCommand(command: Command) {
        if (!isRunning) throw IllegalStateException("CommandSender is already closed")
        scope.launch {
            commandChannel.send(command)
        }
    }

    /**
     * 发送指令并重试
     */
    private suspend fun sendCommandWithRetry(command: Command, retryCount: Int = 0, currentDelay: Long = config.retryDelay) {
        log("Sending command: ${command.id}, retryCount: $retryCount")
        val response = try {
            sendCommand(command)
        } catch (e: Exception) {
            log("Command ${command.id} failed with exception: ${e.message}")
            Response(command.id, false)
        }

        if (response.isSuccess) {
            log("Command ${command.id} succeeded")
            _commandStateFlow.emit(CommandState.Success(command))
        } else if (retryCount < config.maxRetries - 1) {
            log("Retrying command: ${command.id}")
            delay(currentDelay)
            sendCommandWithRetry(command, retryCount + 1, currentDelay * 2) // 指数退避
        } else {
            log("Command ${command.id} failed after ${config.maxRetries} retries")
            _commandStateFlow.emit(CommandState.Failed(command))
        }
    }

    /**
     * 清理资源
     */
    fun cleanup() {
        isRunning = false
        scope.cancel("CommandSender is shutting down")
        commandChannel.close()
        log("CommandSender resources cleaned up")
    }

    /**
     * 日志记录
     */
    private fun log(message: String) {
        println("CommandSender: $message") // 替换为实际日志工具
    }
}

/**
 * 工具类配置
 */
data class CommandSenderConfig(
    val maxRetries: Int = 3,
    val retryDelay: Long = 300,
    val dispatcher: CoroutineDispatcher = Dispatchers.IO
)

/**
 * 指令数据类
 */
data class Command(val id: String, val data: String, val priority: Int = 0)

/**
 * 指令响应数据类
 */
data class Response(val commandId: String, val isSuccess: Boolean)

/**
 * 指令状态密封类
 */
sealed class CommandState {
    data class Pending(val command: Command, val retryCount: Int = 0) : CommandState()
    data class Success(val command: Command) : CommandState()
    data class Failed(val command: Command, val error: Throwable? = null) : CommandState()
    data class Timeout(val command: Command) : CommandState()
    data class Cancelled(val command: Command) : CommandState()
}

2. 在 ViewModel 中使用工具类
kotlin 复制代码
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch

class DeviceControlViewModel : ViewModel() {
    // 创建 CommandSender 实例
    private val commandSender = CommandSender(
        sendCommand = { command ->
            // 模拟发送指令并接收回码
            delay(100) // 模拟网络延迟
            Response(command.id, Math.random() > 0.5) // 随机返回成功或失败
        }
    )

    // 暴露指令状态流
    val commandStateFlow: SharedFlow<CommandState> = commandSender.commandStateFlow

    /**
     * 添加指令
     */
    fun addCommand(command: Command) {
        viewModelScope.launch {
            commandSender.addCommand(command)
        }
    }

    /**
     * 清理资源
     */
    override fun onCleared() {
        super.onCleared()
        commandSender.cleanup()
    }
}

3. 在 ActivityFragment 中观察状态
kotlin 复制代码
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.collect

class DeviceControlActivity : AppCompatActivity() {

    private val viewModel: DeviceControlViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 监听指令状态
        lifecycleScope.launch {
            viewModel.commandStateFlow.collect { state ->
                when (state) {
                    is CommandState.Success -> {
                        // 更新 UI:指令成功
                        println("Command ${state.command.id} succeeded")
                    }
                    is CommandState.Failed -> {
                        // 更新 UI:指令失败
                        println("Command ${state.command.id} failed")
                    }
                    else -> {}
                }
            }
        }

        // 添加指令
        viewModel.addCommand(Command("1", "Turn on"))
        viewModel.addCommand(Command("2", "Turn off"))
    }
}

总结

通过本文,我们实现了一个基于 Kotlin 协程的设备指令控制工具类。该工具类支持指令队列、重试机制、状态管理等功能,并适配安卓平台,确保生命周期管理和主线程安全性。希望这篇博客对你有所帮助!

相关推荐
MyhEhud2 小时前
kotlin flatMap 变换函数的特点和使用场景
开发语言·windows·kotlin
三思而后行,慎承诺3 小时前
Kotlin 常见问题
开发语言·面试·kotlin
百锦再6 小时前
Android Studio开发中Application和Activity生命周期详解
android·java·ide·app·gradle·android studio·studio
Kapaseker6 小时前
你可能不知道的Kotlin Data Class陷阱
kotlin
移动开发者1号6 小时前
Android现代进度条替代方案
android·app
万户猴6 小时前
【Android蓝牙开发实战-11】蓝牙BLE多连接机制全解析1
android·蓝牙
RichardLai886 小时前
[Flutter 基础] - Flutter基础组件 - Icon
android·flutter
前行的小黑炭7 小时前
Android LiveData源码分析:为什么他刷新数据比Handler好,能更节省资源,解决内存泄漏的隐患;
android·kotlin·android jetpack
清霜之辰7 小时前
安卓 Compose 相对传统 View 的优势
android·内存·性能·compose
_祝你今天愉快7 小时前
再看!NDK交叉编译动态库并在Android中调用
android