任务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)

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

Kotlin入门(29)任务Runnable的更多相关文章

  1. Kotlin入门教程——目录索引

    Kotlin是谷歌官方认可的Android开发语言,Android Studio从3.0版本开始就内置了Kotlin,所以未来在App开发中Kotlin取代Java是大势所趋,就像当初Android ...

  2. 写给Android开发者的Kotlin入门

    写给Android开发者的Kotlin入门 转 https://www.jianshu.com/p/bb53cba6c8f4 Google在今年的IO大会上宣布,将Android开发的官方语言更换为K ...

  3. Kotlin入门第二课:集合操作

    测试项目Github地址: KotlinForJava 前文传送: Kotlin入门第一课:从对比Java开始 初次尝试用Kotlin实现Android项目 1. 介绍 作为Kotlin入门的第二课, ...

  4. Kotlin入门(32)网络接口访问

    手机上的资源毕竟有限,为了获取更丰富的信息,就得到辽阔的互联网大海上冲浪.对于App自身,也要经常与服务器交互,以便获取最新的数据显示到界面上.这个客户端与服务端之间的信息交互,基本使用HTTP协议进 ...

  5. Kotlin入门(28)Application单例化

    Application是Android的又一大组件,在App运行过程中,有且仅有一个Application对象贯穿应用的整个生命周期,所以适合在Application中保存应用运行时的全局变量.而开展 ...

  6. Kotlin入门(5)字符串及其格式化

    上一篇文章介绍了数组的声明和操作,包括字符串数组的用法.注意到Kotlin的字符串类也叫String,那么String在Java和Kotlin中的用法有哪些差异呢?这便是本文所要阐述的内容了. 首先要 ...

  7. Kotlin入门(9)函数的基本用法

    上一篇文章介绍了Kotlin新增的空安全机制,控制语句部分可算是讲完了,接下来将连续描述Kotlin如何定义和调用函数,本篇文章先介绍函数的基本用法. 前面几篇文章介绍控制语句之时,在setOnCli ...

  8. Kotlin入门(11)江湖绝技之特殊函数

    上一篇文章介绍了Kotlin对函数的输入参数所做的增强之处,其实函数这块Kotlin还有好些重大改进,集中体现在几类特殊函数,比如泛型函数.内联函数.扩展函数.尾递归函数.高阶函数等等,因此本篇文章就 ...

  9. Kotlin入门(13)类成员的众生相

    上一篇文章介绍了类的简单定义及其构造方式,当时为了方便观察演示结果,在示例代码的构造函数中直接调用toast提示方法,但实际开发是不能这么干的.合理的做法是外部访问类的成员属性或者成员方法,从而获得处 ...

随机推荐

  1. Python——爬虫进阶

    课程内容 Python爬虫——反爬 Python加密与解密 Python模块——HashLib与base64    Python爬虫——selenium模块 Python——pytessercat识别 ...

  2. yolo_v3训练自己的模型(人脸及deep-sort)

    做deep-sort多目标跟踪需要结合yolo_v3进行检测行人 由于我的项目中需要对人脸进行检测,所以需要训练针对人脸的模型 训练样本是来自WIDER-FACE人脸库.(有3w+的图片和标注框) d ...

  3. (转)Apache从2.2换至2.4httpd.conf的调整笔记(windows环境)

    原文:https://www.cnblogs.com/tjws/articles/3469075.html#top 整理一下Windows环境Apache 2.2 改成 Apache 2.4.1后 h ...

  4. TransactionScope事务处理方法介绍及.NET Core中的注意事项

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/10170712.html 今天在写CzarCms的UnitOfWork的使用使用到了这个Transacti ...

  5. 改善JAVA代码01:考虑静态工厂方法代替构造器

    前言 系列文章:[传送门]   每次开始新的一本书,我都会很开心.新书新心情. 正文 静态工厂方法代替构造器 说起这个,好多可以念叨的.做了一年多的项目,慢慢也有感触. 说起构造器 大家很明白,构造器 ...

  6. Mybatis学习(四)————— 高级映射,一对一,一对多,多对多映射

    一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种关系来讲,比如有员工和部 ...

  7. Coder解压探索===冥想补蓝v.1.0

    主题是什么? 这是一篇是我自己在探索冥想术的过程中,有了一些浅薄的收获,所以写出来记录与分享. 我不太记得最早是因为什么原因去学习冥想,一开始对我而言,这个词带有很多成见,诸如“老僧入定”“三界六道” ...

  8. 使用HttpWebRequest请求API接口以及其他网站资源

    很多时候,我们项目需要其他网站的资源,而这个被请求的网站可能属于你们自己开发管理的网站.也可能是公网上其他网站对外开发的API接口,比如说腾讯的微信公众平台的API接口.各大短信服务商的短信API接口 ...

  9. Easyui input 取值跟赋值

    var val = $("#id").textbox('getValue')  //取值 $("#id").textbox('setValue','text') ...

  10. 人工智能第三课:数据科学中的Python

    我用了两天左右的时间完成了这一门课<Introduction to Python for Data Science>的学习,之前对Python有一些基础,所以在语言层面还是比较顺利的,这门 ...