如何每秒运行一个 Runnable 来更新 UI

2024-03-27

我正在尝试在 kotlin android 中编写代码以每秒移动一个图像,但我无法使其工作。现在我正在使用Timer安排一个Timer Task每秒,但它没有按预期工作。

这是我的代码

class Actvt_Image<float> : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_actvt__image)

        val pict_mario = findViewById<ImageView>(R.id.img_Mario)
        val bt_down = findViewById<Button>(R.id.bt_down)
        val frame = findViewById<LinearLayout>(R.id.frame)
        val txt1=findViewById<TextView>(R.id.txt1)

        var i =100
        val timer = Timer()
        val myTask = object : TimerTask() {
            override fun run() {

                txt1.text = (i+1).toString()
                img_Mario.rotation=180f
                img_Mario.translationX +=100
                img_Mario.translationY +=20
            }
        }

        bt_down.setOnClickListener {

            i=0
            timer.schedule(myTask, 1000, 1000)

        }
    }

}

您正在尝试在后台线程上更新 UI,这是不可能的。 UI只能在UI线程上更新。另外,使用Timer and TimerTask每 1 秒创建和销毁一个线程并不是使用线程的正确方法,因为创建线程是一个内存消耗很大的操作。

你需要做的是使用Handler并告诉UI Thread运行一个Runnable在每个所需的间隔之后。消除Timer and TimerTask并使用以下内容

val handler = Handler(Looper.getMainLooper())
handler.post(object : Runnable {
            override fun run() {
                txt1.text = (i+1).toString()
                img_Mario.rotation=180f
                img_Mario.translationX +=100
                img_Mario.translationY +=20

                handler.postDelayed(this, 1000)
            }
        })

上面的代码使用处理程序并将任务发布到 UI 线程消息队列。任务本身正在更新 UI 并使用相同的处理程序再次将其自身发布到 UI 线程消息队列,但这次在 1 秒延迟后使用handler.postDelayed() methond

编辑:如何停止可运行

如果您想停止特定的runnable您可以使用以下方法并传入相同的runnable您传入的对象handler.post()。当然你必须保留对runnable随时阻止它。上面的代码不保留引用。请参阅完整代码 below.

handler.removeCallbacks(runnable) //stops a specific runnable

停止所有剩余的回调或runnable从 UI 线程消息队列中使用这个

handler.removeCallbacksAndMessages(null) //stops any pending callback in message queue

完整代码

注意:我添加了一个停止按钮单击侦听器作为补充

class Actvt_Image<float> : AppCompatActivity() {

        private lateinit var handler : Handler
        private lateinit var runnable : Runnable // reference to the runnable object
        private var i = 0

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_actvt__image)

            val pict_mario = findViewById<ImageView>(R.id.img_Mario)
            val bt_down = findViewById<Button>(R.id.bt_down)
            val bt_stop = findViewById<Button>(R.id.bt_stop)
            val frame = findViewById<LinearLayout>(R.id.frame)
            val txt1=findViewById<TextView>(R.id.txt1)

            handler = Handler(Looper.getMainLooper())
            runnable = Runnable {
                i++
                txt1.text = i.toString()
                img_Mario.rotation=180f
                img_Mario.translationX +=100
                img_Mario.translationY +=20
                handler.postDelayed(runnable, 1000)
            }

            bt_down.setOnClickListener {

                handler.post(runnable)

            }

            bt_stop.setOnClickListener {
                //Use this to stop all callbacks
                //handler.removeCallbacksAndMessages(null)

                handler.removeCallbacks(runnable) 

            }
        }

    }

在这里阅读有关进程、线程和处理程序的更多信息:https://developer.android.com/guide/components/processes-and-threads https://developer.android.com/guide/components/processes-and-threads https://developer.android.com/reference/android/os/Handler https://developer.android.com/reference/android/os/Handler

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何每秒运行一个 Runnable 来更新 UI 的相关文章

随机推荐