zoukankan      html  css  js  c++  java
  • Kotlin入门(29)任务Runnable

    任务Runnable定义了一个可以独立运行的代码片段,通常用于界面控件的延迟处理,比如有时为了避免同时占用某种资源造成冲突,有时则是为了反复间隔刷新界面从而产生动画效果。运行一个任务也有多种形式,既可在UI线程中调用处理器对象的post或者postDelayed方法,也能另外开启分线程来执行Runnable对象。那么在运行任务之前,必须事先声明该任务的对象,然后才能由调用者执行该任务。Kotlin代码声明Runnable对象有四种方式,分别对应不同的业务场景,接下来就依次阐述Runnable对象的四种声明方式:

    第一种:内部类
    内部类方式是最循规蹈矩的,在代码里先书写一个继承自Runnable的内部类,再重写它的run方法,填入具体的业务逻辑处理。以最常见的计数器为例子,每隔一秒便在界面上显示加一后的计数结果,使用内部类方式进行变化的话,就是以下的Kotlin代码:

        private val handler = Handler()
        private var count = 0
        inner private class Counter : Runnable {
            override fun run() {
                count++
                tv_result.text = "当前计数值为:$count"
                handler.postDelayed(this, 1000)
            }
        }
    

    然后在Activity页面的onCreate方法中加上下面一行代码,命令执行这个计数任务:

        handler.post(Counter())
    

    第二种:匿名内部类

    内部类的方式最正规,无疑也是最啰嗦的。由于这个计数任务只在页面打开时启动,因此并不需要对其显式构造,只要在定义内部类时顺便声明任务实例即可。此时的声明代码便从内部类方式变成了匿名内部类方式,采取Kotlin编码的话注意使用关键字object占位,表示这是一个匿名内部类,完整的Kotlin代码如下所示:

        private val counter = object : Runnable {
            override fun run() {
                count++
                tv_result.text = "当前计数值为:$count"
                handler.postDelayed(this, 1000)
            }
        }
    

    因为定义内部类的同时就声明了任务实例,所以处理器直接运行该实例即可启动任务:

        handler.post(counter)
    

    内部类与匿名内部类这两种方式,其实内部都拥有类的完整形态,故而它们的run方法允许使用关键字this指代这个人物类,示例代码中的“handler.postDelayed(this, 1000)”意思是间隔一秒之后重复执行自身任务。正因为能够重复执行任务,所以这两种方式可用于持续刷新界面的动画效果。

    第三种:匿名函数
    前面的两种内部类实现方式,拥有类的完整形态意味着必须显式重写run方法,可是这个任务类肯定且只能重写run方法,即使开发者不写出来,run方法也是逃不掉的。早在第一章,当时为了演示Kotlin代码的间接性,举了一个例子“按钮对象.setOnClickListener { 点击事件的处理代码 }”,这种写法正是采取了Lamba表达式,直接把点击事件接口的唯一方法onClick给省略掉。因此,本节的任务对象也可使用类似的写法,只要说明该对象是Runnable类型,则多余的run方法就能如愿去除。下面是个将任务对象改写后的Kotlin代码:

        private val counter = Runnable {
            count++
            tv_result.text = "当前计数值为:$count"
        }
    

    显而易见,上述的counter仍是Runnable类型,于是处理器依旧运行该实例即可启动任务:

        handler.post(counter)
    

    不过这种写法去掉run方法是有代价的,虽然表面上代码变得简洁,但是并不拥有类的完整结构,其内部的this关键字不再表示任务类自身,而是表示宿主类即Activity活动类了。鉴于这点变化,该方式内部不可再调用处理器的post或者postDelayed方法,意味着此时任务实例无法重复调用自身。因此,采取了匿名函数方式的任务对象,适用于不需要重复刷新的场合。

    第四种:匿名实例
    注意到前面的counter是个经过等号赋值的任务对象,既然这样,不如直接把等号右边的表达式塞进post方法,就像下面的Kotlin代码那样:

        //第1点:在post方法中直接填写Runnable对象的定义代码
        handler.post(Runnable {
            count++
            tv_result.text = "当前计数值为:$count"
        })
    

    上面的代码还可以进一步精简,因为post方法只能输入Runnable类型的参数,所以括号内部的Runnable纯属多余;另外,post方法有且仅有一个输入参数,于是圆括号嵌套大括号稍显繁琐。把这两个冗余之处分别删除与合并,得到了匿名实例版的Kotlin代码:

        //第2点:如果该任务只需执行一次,则可采用匿名实例的方式,直接嵌入任务的执行代码
        handler.post {
            count++
            tv_result.text = "当前计数值为:$count"
        }
    

    上述去掉圆括号的办法,只适合post方法这种仅有一个参数的调用,如果其它方法存在多个输入参数如postDelayed方法,则外层的圆括号仍需予以保留,此时大括号及其内部代码就作为一个函数参数传入。恢复了圆括号的Kotlin调用代码如下所示:

        //第3点:如果是延迟执行任务,则可将匿名实例作为postDelayed的输入参数
        handler.postDelayed({
            count++
            tv_result.text = "当前计数值为:$count"
        }, 1000)
    

    匿名实例方式直接把任务代码写在调用函数之中,意味着这段任务代码无法被其他地方调用,所以它的适用场景更加狭小。匿名函数虽然无法重复调用,但是尚且允许在不同地方多次调用,而匿名实例只能在它待过的地方昙花一现,因此还是要根据实际的业务要求来选择合适的任务方式。

  • 相关阅读:
    vue的组件名称问题
    vue引入js文件时报This dependency was not found:错误
    vue中input输入第一个字符时,光标会消失,需要再次点击才能输入
    vue中url带有#号键,去除方法
    vue路由机制导致的坑,坑,坑
    Python文件读取和数据处理
    python面向对象
    Python PIL库学习笔记
    汉诺塔的python 动画演示
    十九大报告词频分析
  • 原文地址:https://www.cnblogs.com/aqi00/p/9860756.html
Copyright © 2011-2022 走看看