kuikly-coroutines-threading

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Kuikly 协程与多线程编程

Kuikly Coroutine and Multithreading Programming

核心规则

Core Rules

  • Kuikly 线程约束:所有 Kuikly UI 操作(View、Attr、Event、observable、Module 方法、setTimeout 等)只能在 Kuikly 线程调用,Kuikly UI 相关类非线程安全。
  • 异步任务完成后必须回到 Kuikly 线程才能更新 UI 或访问响应式属性。
  • 动态化场景不支持 kotlinx 协程(js 目标平台不支持多线程),只能使用 Module 机制或 Kuikly 内建协程。
  • Kuikly Thread Constraint: All Kuikly UI operations (View, Attr, Event, observable, Module methods, setTimeout, etc.) can only be called in the Kuikly thread. Kuikly UI-related classes are not thread-safe.
  • Must return to Kuikly thread after asynchronous task completion to update UI or access reactive properties.
  • Dynamic scenarios do not support kotlinx coroutines (JS target platform does not support multithreading), only Module mechanism or Kuikly built-in coroutines can be used.

协程实现方式对比

Comparison of Coroutine Implementation Methods

特性回调(无协程)Kuikly 内建协程kotlinx 协程
动态化支持✅ 支持✅ 支持❌ 不支持
依赖库包增量kotlinx 协程库
线程安全不涉及自动保障需要考虑

FeatureCallback (No Coroutine)Kuikly Built-in Coroutinekotlinx Coroutine
Dynamic support✅ Supported✅ Supported❌ Not supported
Dependency package size increaseNoneNonekotlinx coroutine library
Thread safetyNot involvedAutomatically guaranteedNeed to consider

三种协程 API

Three Coroutine APIs

1. Kuikly 内建协程(推荐用于简单异步)

1. Kuikly Built-in Coroutines (Recommended for Simple Asynchronous Tasks)

框架自带,始终在 Kuikly 线程执行,无线程切换开销,支持动态化
API 入口:
  • GlobalScope.launch { ... }
    — 全局作用域
  • lifecycleScope.launch { ... }
    — 绑定 Pager 生命周期(推荐)
  • async { ... }
    /
    await()
    — 并发获取结果
import:
kotlin
import com.tencent.kuikly.core.coroutines.GlobalScope
import com.tencent.kuikly.core.coroutines.launch
import com.tencent.kuikly.core.coroutines.async
import com.tencent.kuikly.core.coroutines.delay
注意: Kuikly 内建协程 API 本身非线程安全,不能在 Kuikly 线程外调用。
Built into the framework, always executed in the Kuikly thread, no thread switching overhead, supports dynamic scenarios.
API Entries:
  • GlobalScope.launch { ... }
    — Global scope
  • lifecycleScope.launch { ... }
    — Bound to Pager lifecycle (Recommended)
  • async { ... }
    /
    await()
    — Concurrent result acquisition
import:
kotlin
import com.tencent.kuikly.core.coroutines.GlobalScope
import com.tencent.kuikly.core.coroutines.launch
import com.tencent.kuikly.core.coroutines.async
import com.tencent.kuikly.core.coroutines.delay
Note: Kuikly built-in coroutine APIs are not thread-safe themselves and cannot be called outside the Kuikly thread.

2. kotlinx.coroutines 库

2. kotlinx.coroutines Library

Kotlin 官方协程库,支持多线程调度器(Dispatchers.Default/IO/Main 等),不支持动态化
接入方式:
gradle
// iOS & Android
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$KOTLINX_COROUTINES_VERSION")
// 鸿蒙
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$KOTLINX_COROUTINES_OHOS_VERSION")
Official Kotlin coroutine library, supports multi-thread dispatchers (Dispatchers.Default/IO/Main, etc.), does not support dynamic scenarios.
Integration Method:
gradle
// iOS & Android
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$KOTLINX_COROUTINES_VERSION")
// HarmonyOS
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$KOTLINX_COROUTINES_OHOS_VERSION")

3. kuiklyx.coroutines 库(切换到 Kuikly 线程)

3. kuiklyx.coroutines Library (Switch to Kuikly Thread)

提供
Dispatchers.Kuikly
调度器和
KuiklyContextScheduler
回调 API,用于从非 Kuikly 线程切回 Kuikly 线程。
接入方式:
gradle
// iOS & Android
implementation("com.tencent.kuiklyx:coroutines:$KUIKLYX_COROUTINES_VERSION")
// 鸿蒙
implementation("com.tencent.kuiklyx:coroutines:$KUIKLYX_COROUTINES_OHOS_VERSION")
协程方式 API:
kotlin
// 启动协程,在 Kuikly 线程执行
GlobalScope.launch(Dispatchers.Kuikly[ctx]) { ... }
// 在协程中切换到 Kuikly 线程
withContext(Dispatchers.Kuikly[ctx]) { ... }
回调方式 API:
kotlin
KuiklyContextScheduler.runOnKuiklyThread(pagerId) { cancel ->
    if (cancel) return  // pager 已销毁
    // 在 Kuikly 线程执行
}

Provides
Dispatchers.Kuikly
dispatcher and
KuiklyContextScheduler
callback API, used to switch back to Kuikly thread from non-Kuikly threads.
Integration Method:
gradle
// iOS & Android
implementation("com.tencent.kuiklyx:coroutines:$KUIKLYX_COROUTINES_VERSION")
// HarmonyOS
implementation("com.tencent.kuiklyx:coroutines:$KUIKLYX_COROUTINES_OHOS_VERSION")
Coroutine-style API:
kotlin
// Launch coroutine, execute in Kuikly thread
GlobalScope.launch(Dispatchers.Kuikly[ctx]) { ... }
// Switch to Kuikly thread in coroutine
withContext(Dispatchers.Kuikly[ctx]) { ... }
Callback-style API:
kotlin
KuiklyContextScheduler.runOnKuiklyThread(pagerId) { cancel ->
    if (cancel) return  // Pager has been destroyed
    // Execute in Kuikly thread
}

场景选择决策树

Scenario Selection Decision Tree

根据需求选择合适的异步编程方式:
需要异步编程?
├── 只需简化回调,无多线程诉求?
│   └── → 方式1:Kuikly 内建协程
├── 需要执行耗时任务 + 支持动态化?
│   └── → 方式2:Module 机制(可配合内建协程)
├── 需要多线程 + 不需要动态化?
│   └── → 方式3:kotlinx 协程 + kuiklyx 协程
└── Compose DSL 页面?
    └── → 方式4:LaunchedEffect + withContext
⚠️ 一致性原则:选择方案时,还需关注当前项目或模块中已有的异步编程方式,应优先保持一致,避免在同一模块中混用多套异步方案。
详细场景示例和代码:见 SCENARIOS.md

Choose the appropriate asynchronous programming method based on requirements:
Need asynchronous programming?
├── Only need to simplify callbacks, no multi-threading requirements?
│   └── → Option 1: Kuikly Built-in Coroutines
├── Need to execute time-consuming tasks + support dynamic scenarios?
│   └── → Option 2: Module Mechanism (can be used with built-in coroutines)
├── Need multi-threading + no dynamic scenario support required?
│   └── → Option 3: kotlinx coroutines + kuiklyx coroutines
└── Compose DSL page?
    └── → Option 4: LaunchedEffect + withContext
⚠️ Consistency Principle: When selecting a solution, you should also pay attention to the existing asynchronous programming methods in the current project or module, and prioritize consistency to avoid mixing multiple sets of asynchronous solutions in the same module.
Detailed scenario examples and code: See SCENARIOS.md

Compose DSL 中的协程

Coroutines in Compose DSL

Compose DSL 页面(继承
ComposeContainer
)使用 kotlinx 协程体系:
kotlin
@Composable
fun MyContent() {
    var data by remember { mutableStateOf("") }
    LaunchedEffect(Unit) {
        // 默认在 Kuikly 线程执行(ComposeDispatcher)
        val result = withContext(Dispatchers.IO) {
            // 在 IO 线程执行耗时任务
            fetchData()
        }
        // 自动回到 Kuikly 线程
        data = result
    }
    Text(text = data)
}
关键点:
  • LaunchedEffect
    默认运行在 Kuikly 线程(通过
    ComposeDispatcher
    调度)
  • 使用
    withContext(Dispatchers.IO)
    切换到 IO 线程执行耗时任务
  • withContext
    返回后自动回到 Kuikly 线程
  • viewModelScope
    也绑定到 Kuikly 线程,ViewModel 销毁时自动取消
Dispatchers.IO 跨平台定义:
kotlin
// commonMain 中声明 expect
internal expect val Dispatchers.IO: CoroutineDispatcher

// androidMain / appleMain / ohosArm64Main
internal actual val Dispatchers.IO: CoroutineDispatcher
    get() = Dispatchers.IO  // 使用平台原生 IO 调度器

// jsMain(不支持多线程)
internal actual val Dispatchers.IO: CoroutineDispatcher
    get() = Dispatchers.Default

Compose DSL pages (inheriting
ComposeContainer
) use the kotlinx coroutine system:
kotlin
@Composable
fun MyContent() {
    var data by remember { mutableStateOf("") }
    LaunchedEffect(Unit) {
        // Default execution in Kuikly thread (via ComposeDispatcher)
        val result = withContext(Dispatchers.IO) {
            // Execute time-consuming task in IO thread
            fetchData()
        }
        // Automatically return to Kuikly thread
        data = result
    }
    Text(text = data)
}
Key Points:
  • LaunchedEffect
    runs in Kuikly thread by default (scheduled via
    ComposeDispatcher
    )
  • Use
    withContext(Dispatchers.IO)
    to switch to IO thread for time-consuming tasks
  • Automatically return to Kuikly thread after
    withContext
    returns
  • viewModelScope
    is also bound to Kuikly thread, and automatically canceled when ViewModel is destroyed
Cross-platform definition of Dispatchers.IO:
kotlin
// Declare expect in commonMain
internal expect val Dispatchers.IO: CoroutineDispatcher

// androidMain / appleMain / ohosArm64Main
internal actual val Dispatchers.IO: CoroutineDispatcher
    get() = Dispatchers.IO  // Use platform-native IO dispatcher

// jsMain (does not support multi-threading)
internal actual val Dispatchers.IO: CoroutineDispatcher
    get() = Dispatchers.Default

线程安全

Thread Safety

线程安全规则

Thread Safety Rules

  • Kuikly UI 相关类(View、Attr、Event、ObservableProperties、GlobalFunctions、Module 方法、Layout 等)非线程安全,只能在 Kuikly 线程访问
  • Kuikly UI-related classes (View, Attr, Event, ObservableProperties, GlobalFunctions, Module methods, Layout, etc.) are not thread-safe and can only be accessed in the Kuikly thread

线程安全验证机制

Thread Safety Verification Mechanism

详细用法和示例:见 THREAD_SAFETY.md
kotlin
override fun willInit() {
    super.willInit()
    Pager.VERIFY_THREAD = true              // 开启线程校验
    Pager.VERIFY_REACTIVE_OBSERVER = true   // 开启 observable 校验
    Pager.verifyFailed { exception ->       // 自定义验证失败处理
        println("线程安全验证失败: ${exception.message}")
        throw exception
    }
}

Detailed usage and examples: See THREAD_SAFETY.md
kotlin
override fun willInit() {
    super.willInit()
    Pager.VERIFY_THREAD = true              // Enable thread verification
    Pager.VERIFY_REACTIVE_OBSERVER = true   // Enable observable verification
    Pager.verifyFailed { exception ->       // Custom verification failure handling
        println("Thread safety verification failed: ${exception.message}")
        throw exception
    }
}

常见陷阱与正确做法

Common Pitfalls and Correct Practices

❌ 错误做法✅ 正确做法
在非 Kuikly 线程直接更新 observable通过
Dispatchers.Kuikly
KuiklyContextScheduler
切回 Kuikly 线程
在非 Kuikly 线程调用 Module 方法Module 的 acquireModule / toNative 等方法需在 Kuikly 线程调用
在动态化场景使用 kotlinx 协程使用 Kuikly 内建协程或 Module 机制
在 Kuikly 线程外调用内建协程 API内建协程 API 只能在 Kuikly 线程调用
忘记处理 Pager 销毁后的回调
KuiklyContextScheduler
回调检查
cancel
参数
verifyFailed
回调中操作 UI
验证失败通常发生在非 Kuikly 线程,不能调用 UI API
Compose 中在 IO 线程更新 State使用
withContext
回到默认调度器后再更新 State

❌ Wrong Practice✅ Correct Practice
Directly update observable in non-Kuikly threadSwitch back to Kuikly thread via
Dispatchers.Kuikly
or
KuiklyContextScheduler
Call Module methods in non-Kuikly threadModule methods like acquireModule / toNative must be called in Kuikly thread
Use kotlinx coroutines in dynamic scenariosUse Kuikly built-in coroutines or Module mechanism
Call built-in coroutine APIs outside Kuikly threadBuilt-in coroutine APIs can only be called in Kuikly thread
Forget to handle callbacks after Pager destructionCheck
cancel
parameter in
KuiklyContextScheduler
callback
Operate UI in
verifyFailed
callback
Verification failures usually occur in non-Kuikly threads, cannot call UI APIs
Update State in IO thread in ComposeUpdate State after returning to default dispatcher via
withContext