簡體   English   中英

Kotlin:每秒調用一次 function

[英]Kotlin: call a function every second

我想為我的游戲創建一個簡單的倒計時,當游戲開始時,我希望每秒調用一次 function:

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

我試過這個:

var secondsLeft = 15

timer.scheduleAtFixedRate(
   object : TimerTask() {

      override fun run() {
         minusOneSecond()
      }

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

但不幸的是,該應用程序停止了,第二次運行 function 被調用

3 周前,我剛開始使用 android 開發和 Kotlin,到目前為止,我了解最多。

在 Xcode 中使用 swift 我使用這條線,我認為類似的東西適用於 Kotlin

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

問題: Timer類使用帶有隊列的后台線程來排隊並按順序執行所有任務。 從您的代碼中,因為您更新了 UI(在minusOneSecond函數中更改 TextView 內容)。 這就是應用程序拋出以下異常並使您的應用程序崩潰的原因。

android.view.ViewRootImpl$CalledFromWrongThreadException:只有創建視圖層次結構的原始線程才能觸摸其視圖。

解決方案:有很多方法可以實現您的任務,但我更喜歡使用Handler類中的post()postDelayed()方法。 因為它簡單易懂。

val mainHandler = Handler(Looper.getMainLooper())

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

更新:來自作者關於如何從 Handler 暫停/恢復任務的評論。 這是一個例子。

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

我正在使用此代碼每分鍾更新一個時鍾

 fixedRateTimer("timer", false, 0L, 60 * 1000) {
     this@FullscreenActivity.runOnUiThread {
         tvTime.text = SimpleDateFormat("dd MMM - HH:mm", Locale.US).format(Date())
     }
 }

所以你必須用參數1000而不是60*1000來運行它

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

您也可以為此目的使用 CountDownTimer。 因為這需要兩個參數(總時間和間隔時間)
此外,它還提供了一個 on finish 方法來在總時間完成后執行任何任務。

請用

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

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

我每秒都在像這樣調用我的函數

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

我在協程中使用遞歸非常簡單

  private fun loop() {
    CoroutineScope(IO).launch {
        delay(5000)
        CoroutineScope(Main).launch {
            ManagerToWorker()
            loop()
        }
    }
}

我的解決方案

viewModelScope.launch(Dispatchers.IO) {
            while(isActive) {
                when(val response = repository.getApi()) {
                    is NetworkState.Success -> {
                        getAllData.postValue(response.data)
                    }
                    is NetworkState.Error -> this@MainViewModel.isActive = false
                }

                delay(API_CALL_DELAY)
            }
        }
var isActionAcheived = false
var secondsPassed = 0
fun cDTimer(){
    if (!isActionAcheived && secondsPassed < 10){  // repeat check if Action NOT Aceived for max of 10 seconds 
        Handler(Looper.getMainLooper()).postDelayed({
            repeatThisFunction()
            repeater()
            secondsPassed++
        }, 1000) //one second till next execution
    }
}

fun repeater(){
    cDTimer()
}

如果您使用任何后台任務或后台服務,請嘗試此代碼

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

如果您使用 UI 其他人,例如更新 UI 布局,請嘗試此代碼

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM