Я пытаюсь реализовать таймер Android в Kotlin, который будет запускать событие в определенный промежуток времени. Я не хочу использовать TimerTask из-за его задокументированных недостатков (см. Здесь) и, хотя есть потенциально другие способы чтобы сделать это, я хотел бы использовать Handler / Runnable в цикле с задержкой. В Java это возможно, поскольку Runnable может ссылаться на себя в инициализаторе, однако в Kotlin кажется, что это невозможно:

private fun startBoutiqueRefreshTimer(delayMs: Long) {
    val handler = Handler()
    val runnable = Runnable() {
        EventManager.post(BoutiqueRefreshTimerEvent())
        handler.postDelayed(runnable, delayMs)
    }
    handler.postDelayed(runnable, delayMs)
}

Потому что runnable не может быть разрешен во внутреннем вызове postDelayed. Kotlin, очевидно, предотвращает ссылки на переменные из своих собственных инициализаторов.

Каково было бы хорошее решение этой проблемы, все еще используя подход Handler / Runnable?

6
Michael Scott 1 Сен 2017 в 16:55

4 ответа

Лучший ответ

Вы можете переместить подпрограмму, которую вы хотите периодически выполнять, в отдельную функцию:

val runnable = Runnable { doJob() }

fun doJob() {
    EventManager.post(BoutiqueRefreshTimerEvent())
    handler.postDelayed(runnable, delayMs)
}

Обратите внимание, что переменная runnable должна быть доступна в области действия функции doJob (), это означает, что она должна быть членом класса, если вы находитесь в классе / объекте.

4
Piwo 1 Сен 2017 в 13:59

Это сработало для меня, где обработчик использует postDelayed

    override fun onCreateView(inflater: LayoutInflater?, container: 
    ViewGroup?, savedInstanceState: Bundle?): View? {
    val handler = Handler()
    handler.postDelayed(mSplashHandler,1500)
    return view
    }

   internal var mSplashHandler: Runnable = Runnable {
   // your code to do after handler completes
   }
0
Divya 9 Мар 2018 в 13:52

Это будет работать

val updateHandler = Handler()

    val runnable = Runnable {
        updateDisplay() // some action(s)
    }

    updateHandler.postDelayed(runnable, 5000).

private fun updateDisplay() {
      Do actions
}

Или, если вы не слишком знакомы с Kotlin, напишите свой код и преобразуйте код Android в Kotlin, используя Ctrl + Alt + Shift + < KBD > K » .

7
mx0 2 Сен 2017 в 10:49

Вы также можете использовать что-то вроде этого:

private fun startBoutiqueRefreshTimer(delayMs: Long) {
    Handler().apply {
        val runnable = object : Runnable {
            override fun run() {
                EventManager.post(BoutiqueRefreshTimerEvent())
                postDelayed(this, delayMs)
            }
        }
        postDelayed(runnable, delayMs)
    }
}

Я использовал здесь apply() функцию для упрощения переменной Handler и выражение объекта чтобы разрешить ссылку на Runnable.

Как вы можете видеть, когда я использовал выражение объекта для инициализации Runnable (вместо лямбда-выражения), я мог использовать this для ссылки на Runnable объект.

6
Kamil Kamiński 1 Сен 2017 в 14:40