Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问clear审计提醒

android-kotlin-coroutinesandroid kotlin 协程

Agent Skill

android-kotlin-coroutines 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

2,012

周安装

83

GitHub Stars

142

下载量

657
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:android-kotlin-coroutines(android kotlin 协程)
来源仓库:https://github.com/thebushidocollective/han
仓库路径:skills/android-kotlin-coroutines
安装命令:
npx skills add https://github.com/thebushidocollective/han --skill android-kotlin-coroutines
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/thebushidocollective/han --skill android-kotlin-coroutines

简介

用于查找、检索和筛选 Android Kotlin 协程相关异步编程信息。

  • 适用于使用 Kotlin coroutines 和 Flow 进行异步操作、后台任务处理的场景。
  • 提供 viewModelScope、Deferred 返回值、异常处理和 UI 状态更新等具体实现模式。
  • 安装命令:npx skills add https://github.com/thebushidocollective/han --skill android-kotlin-coroutines
  • 注意权限范围和维护状态,避免触发不必要的联网或文件操作。

SKILL.md

Android - Kotlin Coroutines

Asynchronous programming patterns using Kotlin coroutines and Flow in Android.

Key Concepts

Coroutine Basics

// Launching coroutines
class UserViewModel : ViewModel() {

    fun loadUser(id: String) {
        // viewModelScope is automatically cancelled when ViewModel is cleared
        viewModelScope.launch {
            try {
                val user = userRepository.getUser(id)
                _uiState.value = UiState.Success(user)
            } catch (e: Exception) {
                _uiState.value = UiState.Error(e.message)
            }
        }
    }

    // For operations that return a value
    fun fetchUserAsync(id: String): Deferred<User> {
        return viewModelScope.async {
            userRepository.getUser(id)
        }
    }
}

// Suspend functions
suspend fun fetchUserFromNetwork(id: String): User {
    return withContext(Dispatchers.IO) {
        api.getUser(id)
    }
}

Dispatchers

// Main - UI operations
withContext(Dispatchers.Main) {
    textView.text = "Updated"
}

// IO - Network, database, file operations
withContext(Dispatchers.IO) {
    val data = api.fetchData()
    database.save(data)
}

// Default - CPU-intensive work
withContext(Dispatchers.Default) {
    val result = expensiveComputation(data)
}

// Custom dispatcher for limited parallelism
val limitedDispatcher = Dispatchers.IO.limitedParallelism(4)

Flow Basics

// Creating flows
fun getUsers(): Flow<List<User>> = flow {
    while (true) {
        val users = api.getUsers()
        emit(users)
        delay(30_000) // Poll every 30 seconds
    }
}

// Flow from Room
@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    fun getAllUsers(): Flow<List<UserEntity>>
}

// Collecting flows
viewModelScope.launch {
    userRepository.getUsers()
        .catch { e -> _uiState.value = UiState.Error(e) }
        .collect { users ->
            _uiState.value = UiState.Success(users)
        }
}

StateFlow and SharedFlow

class SearchViewModel : ViewModel() {
    // StateFlow - always has a current value
    private val _searchQuery = MutableStateFlow("")
    val searchQuery: StateFlow<String> = _searchQuery.asStateFlow()

    // SharedFlow - for events without initial value
    private val _events = MutableSharedFlow<UiEvent>()
    val events: SharedFlow<UiEvent> = _events.asSharedFlow()

    // Derived state from flow
    val searchResults: StateFlow<List<Item>> = _searchQuery
        .debounce(300)
        .filter { it.length >= 2 }
        .flatMapLatest { query ->
            searchRepository.search(query)
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )

    fun updateQuery(query: String) {
        _searchQuery.value = query
    }

    fun sendEvent(event: UiEvent) {
        viewModelScope.launch {
            _events.emit(event)
        }
    }
}

Best Practices

Structured Concurrency

// Good: Using coroutineScope for parallel operations
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val userDeferred = async { userRepository.getUser() }
    val ordersDeferred = async { orderRepository.getOrders() }
    val notificationsDeferred = async { notificationRepository.getNotifications() }

    // All complete or all fail together
    Dashboard(
        user = userDeferred.await(),
        orders = ordersDeferred.await(),
        notifications = notificationsDeferred.await()
    )
}

// With timeout
suspend fun loadWithTimeout(): Data {
    return withTimeout(5000) {
        api.fetchData()
    }
}

// Or with nullable result on timeout
suspend fun loadWithTimeoutOrNull(): Data? {
    return withTimeoutOrNull(5000) {
        api.fetchData()
    }
}

Exception Handling

// Using runCatching
suspend fun safeApiCall(): Result<User> = runCatching {
    api.getUser()
}

// Handling in ViewModel
fun loadUser() {
    viewModelScope.launch {
        safeApiCall()
            .onSuccess { user ->
                _uiState.value = UiState.Success(user)
            }
            .onFailure { error ->
                _uiState.value = UiState.Error(error.message)
            }
    }
}

// SupervisorJob for independent child failures
class MyViewModel : ViewModel() {
    private val supervisorJob = SupervisorJob()
    private val scope = CoroutineScope(Dispatchers.Main + supervisorJob)

    fun loadMultiple() {
        scope.launch {
            // This failure won't cancel other children
            userRepository.getUser()
        }
        scope.launch {
            // This continues even if above fails
            orderRepository.getOrders()
        }
    }
}

Flow Operators

// Transformation operators
userRepository.getUsers()
    .map { users -> users.filter { it.isActive } }
    .distinctUntilChanged()
    .collect { activeUsers -> updateUI(activeUsers) }

// Combining flows
val combined: Flow<Pair<User, Settings>> = combine(
    userRepository.getUser(),
    settingsRepository.getSettings()
) { user, settings ->
    Pair(user, settings)
}

// FlatMapLatest for search
searchQuery
    .debounce(300)
    .flatMapLatest { query ->
        if (query.isEmpty()) flowOf(emptyList())
        else searchRepository.search(query)
    }
    .collect { results -> updateResults(results) }

// Retry with exponential backoff
api.fetchData()
    .retry(3) { cause ->
        if (cause is IOException) {
            delay(1000 * (2.0.pow(retryCount)).toLong())
            true
        } else false
    }

Lifecycle-Aware Collection

// In Compose - collectAsStateWithLifecycle
@Composable
fun UserScreen(viewModel: UserViewModel = hiltViewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    UserContent(uiState)
}

// In Activity/Fragment - repeatOnLifecycle
class UserFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect { state ->
                    updateUI(state)
                }
            }
        }
    }
}

// Multiple flows
viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        launch {
            viewModel.users.collect { updateUserList(it) }
        }
        launch {
            viewModel.events.collect { handleEvent(it) }
        }
    }
}

Common Patterns

Repository Pattern with Flow

class UserRepository(
    private val api: UserApi,
    private val dao: UserDao,
    private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) {
    fun getUser(id: String): Flow<User> = flow {
        // Emit cached data first
        dao.getUser(id)?.let { emit(it.toDomain()) }

        // Fetch from network
        val networkUser = api.getUser(id)
        dao.insertUser(networkUser.toEntity())
        emit(networkUser.toDomain())
    }
    .flowOn(dispatcher)
    .catch { e ->
        // Log error, emit from cache if available
        dao.getUser(id)?.let { emit(it.toDomain()) }
            ?: throw e
    }

    suspend fun refreshUsers() {
        withContext(dispatcher) {
            val users = api.getUsers()
            dao.deleteAll()
            dao.insertAll(users.map { it.toEntity() })
        }
    }
}

Cancellation Handling

suspend fun downloadFile(url: String): ByteArray {
    return withContext(Dispatchers.IO) {
        val connection = URL(url).openConnection()
        connection.inputStream.use { input ->
            val buffer = ByteArrayOutputStream()
            val data = ByteArray(4096)

            while (true) {
                // Check for cancellation
                ensureActive()

                val count = input.read(data)
                if (count == -1) break
                buffer.write(data, 0, count)
            }

            buffer.toByteArray()
        }
    }
}

// Cancellable flow
fun pollData(): Flow<Data> = flow {
    while (currentCoroutineContext().isActive) {
        emit(api.fetchData())
        delay(5000)
    }
}

Debounce and Throttle

// Debounce - wait for pause in emissions
@Composable
fun SearchField(onSearch: (String) -> Unit) {
    var query by remember { mutableStateOf("") }

    LaunchedEffect(query) {
        delay(300) // Debounce
        if (query.isNotEmpty()) {
            onSearch(query)
        }
    }

    TextField(value = query, onValueChange = { query = it })
}

// In ViewModel
private val _searchQuery = MutableStateFlow("")

val searchResults = _searchQuery
    .debounce(300)
    .distinctUntilChanged()
    .flatMapLatest { query ->
        searchRepository.search(query)
    }
    .stateIn(viewModelScope, SharingStarted.Lazily, emptyList())

Anti-Patterns

GlobalScope Usage

Bad:

GlobalScope.launch {  // Never cancelled, leaks memory
    fetchData()
}

Good:

viewModelScope.launch {  // Properly scoped
    fetchData()
}

Blocking Calls on Main Thread

Bad:

fun loadData() {
    runBlocking {  // Blocks main thread!
        api.fetchData()
    }
}

Good:

fun loadData() {
    viewModelScope.launch {
        withContext(Dispatchers.IO) {
            api.fetchData()
        }
    }
}

Flow Collection Without Lifecycle

Bad:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    lifecycleScope.launch {
        viewModel.uiState.collect {  // Collects even when in background
            updateUI(it)
        }
    }
}

Good:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    viewLifecycleOwner.lifecycleScope.launch {
        viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
            viewModel.uiState.collect { updateUI(it) }
        }
    }
}

Creating New Flow on Each Call

Bad:

// Creates new flow each time
fun getUsers(): Flow<List<User>> = userDao.getAllUsers()

// Called multiple times, multiple database subscriptions

Good:

// Shared flow, single subscription
val users: StateFlow<List<User>> = userDao.getAllUsers()
    .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())

Related Skills

  • android-jetpack-compose: UI integration with coroutines
  • android-architecture: Architectural patterns using coroutines

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Gemini CLI

30.56%
按下载量换算201

Claude Code

23.5%
按下载量换算154

Antigravity

16.3%
按下载量换算107

OpenCode

14.21%
按下载量换算93

Cursor

7.46%
按下载量换算49

Codex

3.76%
按下载量换算25

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。

来源信息

继续浏览同类 Skills