无法在 Kotlin 多平台中访问fixedRateTimer

Ami*_*mir 4 kotlin kotlin-multiplatform

我正在开发一个 Kotlin 多平台项目。我正在尝试使用计时器和倒计时器,但我无法访问kotlin.concurrent.fixedRateTimerimport kotlin.concurrent.timercommonMain模块中。

在此输入图像描述

但是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")
                //...
            }
        }
        //...
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否可以在那里使用这些方法。如果没有,我如何在模块中编写计时器和倒计时器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()
    }
Run Code Online (Sandbox Code Playgroud)

sha*_*eep 6

正如 Qaz 所说,您尝试在通用代码中使用的功能仅限于 JVM

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

  1. 使用其他库(例如moko-time) - 搜索库的最佳位置是这里
  2. expect通过/actual机制使用原生框架类

只是为了给您提供可以做什么的示例(不确定这是否适合您或可以满足您的需求。这只是为了让您朝着正确的方向前进,最重要的是我写的内容根本无法投入生产[-;)

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
}

Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)