无法在 Kotlin Multiplatform 中访问 fixedRateTimer

Cannot access fixedRateTimer in Kotlin Multiplatform

我正在从事 Kotlin Multiplatform 项目。我正在尝试使用计时器和倒计时计时器,但我无法访问 commonMain 模块中的 kotlin.concurrent.fixedRateTimerimport kotlin.concurrent.timer

但是 kotlin.concurrent 可用:

这是根 build.gradle :

plugins {
    kotlin("multiplatform")
    id("com.android.library")
    id("kotlin-android-extensions")
}

// ...

kotlin {
    //...
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("org.jetbrains.kotlin:kotlin-stdlib:1.4.10")
                implementation("org.jetbrains.kotlin:kotlin-reflect:1.4.10")
                implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9")
                //...
            }
        }
        //...
    }
}

我想知道是否可以在那里使用这些方法。如果没有,如何在commonMain模块中写一个定时器和倒数定时器?

我曾尝试使用 Coroutines 实现相同的功能但失败了,因为它们不精确:

    fun doAfter(delay: Long, action: () -> (Unit)) = launch {
        delay(delay)
        action.invoke()
    }

    fun countdown(time: Long, tick: Long, onTick: () -> (Unit), onFinish: () -> (Unit)) = launch {
        val ticks = (time / tick).toInt()
        repeat(ticks) {
            onTick()
            delay(tick)
        }
        onFinish()
    }

您尝试使用的功能仅限于 JVM。看 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/fixed-rate-timer.html

正如 Qaz 所说,您尝试在公共代码中使用的函数是 JVM only

通常在 KMP 中,当您仍然没有框架内置的通用功能时,您可以采用不同的方法:

  1. 使用其他库(例如 moko-time) - Best place for searching libraries is here
  2. 通过expect/actual机制
  3. 使用原生框架类

只是给你和可以做什么的例子(不确定这是否适合你或是否能满足你的需要。这只是为了让你朝着正确的方向前进,最重要的是我写的东西不能做好生产准备 [-;)

commonMain:Timer.kt

expect class KMMTimer(
    name: String? = null,
    interval: Long,
    delay: Long,
    action: () -> Unit
) {
    val name: String?
    val interval: Long
    val delay: Long

    fun start()
    fun cancel()
    fun isRunning(): Boolean
}

androidMain:Timer.kt

import java.util.*
import kotlin.concurrent.fixedRateTimer

actual class KMMTimer actual constructor(
    actual val name: String?,
    actual val interval: Long,
    actual val delay: Long,
    action: () -> Unit
) {
    private var timer: Timer? = null
    private val action = action

    actual fun start() {
        if (!isRunning()) {
            timer = fixedRateTimer(
                name = name,
                initialDelay = delay,
                period = interval
            ) {
                action()
            }
        }
    }

    actual fun cancel() {
        timer?.cancel()
        timer = null
    }

    actual fun isRunning(): Boolean {
        return timer != null
    }
}

iosMain:Timer.kt

import platform.Foundation.NSDate
import platform.Foundation.NSRunLoop
import platform.Foundation.NSRunLoopCommonModes
import platform.Foundation.NSTimer

actual class KMMTimer actual constructor(
    actual val name: String?,
    actual val interval: Long,
    actual val delay: Long,
    action: () -> Unit
) {
    private var timer: NSTimer? = null
    private var action = action

    actual fun start() {
        if (!isRunning()) {
            timer = NSTimer(
                fireDate = NSDate(
                    NSDate().timeIntervalSinceReferenceDate + (delay.toDouble() / 1000)
                ),
                interval = (interval.toDouble() / 1000),
                repeats = true,
                block = {
                    action()
                }
            )
            timer?.let {
                NSRunLoop.currentRunLoop().addTimer(it, NSRunLoopCommonModes)
            }
        }
    }

    actual fun cancel() {
        timer?.invalidate()
        timer = null
    }

    actual fun isRunning(): Boolean {
        return timer != null
    }
}