Kotlin: jede Sekunde eine Funktion aufrufen

Lesezeit: 4 Minuten

Ich möchte einen einfachen Countdown für mein Spiel erstellen, wenn das Spiel beginnt, möchte ich, dass diese Funktion jede Sekunde aufgerufen wird:

fun minusOneSecond(){
  if secondsLeft > 0{
     secondsLeft -= 1
     seconds_thegame.text = secondsLeft.toString()
  }
}

Ich habe das versucht:

var secondsLeft = 15

timer.scheduleAtFixedRate(
   object : TimerTask() {

      override fun run() {
         minusOneSecond()
      }

    },0, 1000
)   // 1000 Millisecond  = 1 second

Aber die App bricht leider ab, beim 2ten Aufruf der Run-Funktion

Ich habe erst vor 3 Wochen mit der Android-Entwicklung und Kotlin angefangen und bisher verstehe ich das Beste daraus.

Mit Swift in Xcode verwende ich diese Zeile und ich dachte, etwas Ähnliches würde mit Kotlin funktionieren

setTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(minusOneSecond), userInfo: nil, repeats: true)

  • Mögliches Duplikat von How to call a function after delay in Kotlin?

    – nologin

    8. April 2019 um 10:14 Uhr

  • Der runOnUiThread ist erforderlich, da die Benutzeroberfläche nur von einem UI-Thread aus bearbeitet werden kann und der Rückruf in einem temporären Hintergrundthread erfolgt.

    – Eugen Petrenko

    8. April 2019 um 10:15 Uhr

  • Wie wäre es mit einer AsyncTask ? Mit einer Hintergrundaufgabe, die aus einer Schleife besteht, die eine Sekunde wartet und dann den Fortschritt aktualisiert. Und eine onProgressUpdate()-Methode, die Ihre Benutzeroberfläche aktualisiert.

    – Vincrichaud

    8. April 2019 um 10:17 Uhr

Benutzeravatar von Son Truong
Sohn Truong

Problem: Timer -Klasse verwendet einen Hintergrundthread mit einer Warteschlange, um alle Aufgaben in eine Warteschlange einzureihen und nacheinander auszuführen. Aus Ihrem Code, da Sie die Benutzeroberfläche aktualisieren (Ändern des TextView-Inhalts in minusOneSecond Funktion). Aus diesem Grund löst die App die folgende Ausnahme aus und lässt Ihre App abstürzen.

android.view.ViewRootImpl$CalledFromWrongThreadException: Nur der ursprüngliche Thread, der eine Ansichtshierarchie erstellt hat, kann seine Ansichten berühren.

Lösung: Es gibt viele Möglichkeiten, Ihre Aufgabe zu erfüllen, aber ich bevorzuge die Verwendung Post() und postVerzögert() Methode aus Handler Klasse. Weil es einfach und leicht verständlich ist.

val mainHandler = Handler(Looper.getMainLooper())

mainHandler.post(object : Runnable {
    override fun run() {
        minusOneSecond()
        mainHandler.postDelayed(this, 1000)
    }
})

Aktualisieren: Aus dem Kommentar des Autors zum Anhalten/Fortsetzen der Aufgabe von Handler. Hier ist ein Beispiel.

class MainActivityKt : AppCompatActivity() {

    lateinit var mainHandler: Handler

    private val updateTextTask = object : Runnable {
        override fun run() {
            minusOneSecond()
            mainHandler.postDelayed(this, 1000)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Your logic code
        ...
        mainHandler = Handler(Looper.getMainLooper())
    }

    override fun onPause() {
        super.onPause()
        mainHandler.removeCallbacks(updateTextTask)
    }

    override fun onResume() {
        super.onResume()
        mainHandler.post(updateTextTask)
    }

    fun minusOneSecond() {
        if secondsLeft > 0 {
            secondsLeft -= 1
            seconds_thegame.text = secondsLeft.toString()
        }
    }
}

Ich verwende diesen Code, um jede Minute eine Uhr zu aktualisieren

 fixedRateTimer("timer", false, 0L, 60 * 1000) {
     [email protected] {
         tvTime.text = SimpleDateFormat("dd MMM - HH:mm", Locale.US).format(Date())
     }
 }

Sie müssen es also mit Paratemer ausführen 1000 Anstatt von 60*1000

val timer = object: CountDownTimer(10000, 1000) {
    override fun onTick(millisUntilFinished: Long) {
        // do something
    }
    override fun onFinish() {
        // do something
    }
}
timer.start()

Sie können zu diesem Zweck auch CountDownTimer verwenden. Da dies zwei Parameter benötigt (die Gesamtzeit und die Intervallzeit)

Außerdem bietet es eine On-Finish-Methode, um jede Aufgabe auszuführen, wenn die Gesamtzeit abgelaufen ist.

  • Das ist nicht gut. Es beschränkt Sie darauf, die maximale Zeit im Voraus zu kennen, und endet, wenn diese Zeit erreicht ist.

    – Johannes

    29. April 2021 um 16:08 Uhr

Benutzeravatar von Sandy Genedy
Sandy Genedy

bitte verwende

inline fun Timer.schedule(
    time: Date, 
    period: Long, 
    crossinline action: TimerTask.() -> Unit
): TimerTask

Hinweis: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.concurrent/java.util.-timer/schedule.html

Ich rufe meine Funktion jede Sekunde so auf

val handler = Handler()
  handler.postDelayed(object : Runnable {
      override fun run() {
            //Call your function here
            handler.postDelayed(this, 1000)//1 sec delay
        }
}, 0)

  • Warum 0 da drüben setzen?

    – Arbaz.in

    7. Oktober 2021 um 4:40 Uhr

Benutzeravatar von Thiago
Thiago

Meine Lösung

viewModelScope.launch(Dispatchers.IO) {
            while(isActive) {
                when(val response = repository.getApi()) {
                    is NetworkState.Success -> {
                        getAllData.postValue(response.data)
                    }
                    is NetworkState.Error -> [email protected] = false
                }

                delay(API_CALL_DELAY)
            }
        }

  • Warum 0 da drüben setzen?

    – Arbaz.in

    7. Oktober 2021 um 4:40 Uhr

Benutzeravatar von milan pithadia
Mailand Pithadia

Wenn Sie eine Hintergrundaufgabe oder einen Hintergrunddienst verwenden, versuchen Sie diesen Code

val timer = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({
            Log.d("RUNNING ","Thread")
        },0,10,TimeUnit.SECONDS)

Wenn Sie mit UI-Themen wie dem Update des UI-Layouts arbeiten, versuchen Sie diesen Code

val timer = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate({
            Log.d("RUNNING ","BACKGROUN Thread")
            runOnUiThread {
                Log.d("RUNNING ","Update UI Thread")
                btnUpdate.setText(System.currentTimeMillis().toString())
            }
        },0,1,TimeUnit.SECONDS)

1431710cookie-checkKotlin: jede Sekunde eine Funktion aufrufen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy