在安卓开发中,设备控制是一个常见的需求。本文将介绍如何使用 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. 在 Activity
或 Fragment
中观察状态
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 协程的设备指令控制工具类。该工具类支持指令队列、重试机制、状态管理等功能,并适配安卓平台,确保生命周期管理和主线程安全性。希望这篇博客对你有所帮助!