Не удается получить доступ к fixedRateTimer в мультиплатформенной Kotlin

#kotlin #kotlin-multiplatform

#kotlin #kotlin-мультиплатформенный

Вопрос:

Я работаю над мультиплатформенным проектом Kotlin. И я пытаюсь использовать таймер и таймер обратного отсчета, но я не могу получить доступ kotlin.concurrent.fixedRateTimer к модулю или import kotlin.concurrent.timer в commonMain модуле.

введите описание изображения здесь

Однако kotlin.concurrent доступно: введите описание изображения здесь

Это root 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()
    }
  

Ответ №1:

Как сказал Qaz, функция, которую вы пытаетесь использовать в обычном коде, предназначена только для JVM.

Обычно в KMP, когда у вас все еще нет общей функциональности, уже встроенной в фреймворк, вы можете использовать разные подходы:

  1. Используйте чужую библиотеку (например, moko-time) — лучшее место для поиска библиотек здесь.
  2. Используйте собственные классы framworks с помощью механизма 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
}

  

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
    }
}
  

Ответ №2:

Функция, которую вы пытаетесь использовать, предназначена только для JVM. See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/fixed-rate-timer.html

Комментарии:

1. Как я могу добиться такой же функциональности там?