Kotlin:每秒调用一个函数

时间:2019-04-08 10:10:21

标签: android kotlin

我想为我的游戏创建一个简单的倒计时,当游戏开始时,我希望每秒调用一次此函数:

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

但是不幸的是,应用程序停止了,第二次调用运行功能

3周前,我才刚开始进行android开发和Kotlin开发,到目前为止,我对它的了解最多。

借助Xcode的快速处理,我使用了这一行,并且我认为类似的方法也可以在Kotlin中使用

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

7 个答案:

答案 0 :(得分:4)

问题: Timer类使用带有队列的后台线程来按顺序排队并执行所有任务。从代码中,因为您更新了UI(更改minusOneSecond函数中的TextView内容)。这就是为什么该应用程序引发以下异常并使您的应用程序崩溃的原因。

  

android.view.ViewRootImpl $ CalledFromWrongThreadException:仅   创建视图层次结构的原始线程可以触摸其视图。

解决方案:有很多方法可以完成您的任务,但我更喜欢使用{{的 post() postDelayed()方法3}}类。因为它简单易懂。

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

答案 1 :(得分:3)

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

您也可以为此使用CountDownTimer。因为这需要两个参数(总时间和间隔时间)
此外,它还提供了一种完成方法,可以在总时间结束后执行任何任务。

答案 2 :(得分:2)

我正在使用此代码每分钟更新一次时钟

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

所以您必须使用paratemer 1000而不是60*1000来运行它

答案 3 :(得分:1)

我在Coroutine中使用递归非常简单

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

答案 4 :(得分:0)

请使用

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

答案 5 :(得分:0)

我每秒这样调用我的函数

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

答案 6 :(得分:0)

我的解决方案

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