前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin入门(29)任务Runnable

Kotlin入门(29)任务Runnable

作者头像
aqi00
发布2019-01-18 15:57:40
1.8K0
发布2019-01-18 15:57:40
举报
文章被收录于专栏:老欧说安卓老欧说安卓

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

第一种:内部类

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

代码语言:javascript
复制
    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方法中加上下面一行代码,命令执行这个计数任务:

代码语言:javascript
复制
    handler.post(Counter())

第二种:匿名内部类

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

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

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

代码语言:javascript
复制
    handler.post(counter)

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

第三种:匿名函数

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

代码语言:javascript
复制
    private val counter = Runnable {
        count++
        tv_result.text = "当前计数值为:$count"
    }

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

代码语言:javascript
复制
    handler.post(counter)

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

第四种:匿名实例

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

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

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

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

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

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

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

点此查看Kotlin入门教程的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年10月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一种:内部类
  • 第二种:匿名内部类
  • 第三种:匿名函数
  • 第四种:匿名实例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档