继上一篇文章介绍了项目中所使用的Kotlin特性,本文继续整理当前项目所用到的特性。java
with、apply、run函数都是Kotlin标准库中的函数。with在第一篇文章中已经介绍过。android
apply函数是指在函数块内能够经过 this 指代该对象,返回值为该对象本身。在链式调用中,能够考虑使用它来不破坏链式。git
/** * Calls the specified function [block] with `this` value as its receiver and returns `this` value. */
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
复制代码
举个例子:github
/** * Created by tony on 2018/4/26. */
object Test {
@JvmStatic
fun main(args: Array<String>) {
val result ="Hello".apply {
println(this+" World")
this+" World"
}
println(result)
}
}
复制代码
执行结果:闭包
Hello World
Hello
复制代码
第一个字符串是在闭包中打印的,第二个字符串是result的结果,它仍然是“Hello”。架构
run函数相似于apply函数,可是run函数返回的是最后一行的值。app
/** * Calls the specified function [block] with `this` value as its receiver and returns its result. */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
复制代码
举个例子:函数
/** * Created by tony on 2018/4/26. */
object Test {
@JvmStatic
fun main(args: Array<String>) {
val result ="Hello".run {
println(this+" World")
this + " World"
}
println(result)
}
}
复制代码
执行结果:工具
Hello World
Hello World
复制代码
第一个字符串是在闭包中打印的,第二个字符串是result的结果,它返回的是闭包中最后一行的值,因此也打印“Hello World”。布局
在App的反馈页面中,须要输入邮箱、主题、内容才能完成反馈按钮的提交。
最初的写法是这样:
if (viewModel.email.value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_email_address)).show()
return@onClickRight
}
if (!Util.checkEmail(viewModel.email.value!!)) {
toast(resources.getString(R.string.the_email_format_you_have_filled_is_incorrect)).show()
return@onClickRight
}
if (viewModel.subject.value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_feedback_subject)).show()
return@onClickRight
}
if (viewModel.content.value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_details)).show()
return@onClickRight
}
复制代码
修改为只使用apply函数
viewModel.apply {
if (email.value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_email_address)).show()
return@onClickRight
}
if (!Util.checkEmail(email.value!!)) {
toast(resources.getString(R.string.the_email_format_you_have_filled_is_incorrect)).show()
return@onClickRight
}
if (subject.value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_feedback_subject)).show()
return@onClickRight
}
if (content.value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_details)).show()
return@onClickRight
}
}
复制代码
感受不够cool,能够结合run和apply函数一块儿使用
viewModel.email.run {
if (value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_email_address)).show()
return@onClickRight
}
if (!Util.checkEmail(value!!)) {
toast(resources.getString(R.string.the_email_format_you_have_filled_is_incorrect)).show()
return@onClickRight
}
viewModel
}.subject.run {
if (value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_feedback_subject)).show()
return@onClickRight
}
viewModel
}.content.apply {
if (value!!.isEmpty()) {
toast(resources.getString(R.string.you_have_not_completed_the_details)).show()
return@onClickRight
}
}
复制代码
Kotlin的data class有点相似于Scala的case class。
如下的Java Bean代码
/** * Created by tony on 2018/4/27. */
public class User {
public String userName;
public String password;
}
复制代码
等价于
data class User (var userName: String? = null,var password: String? = null)
复制代码
能够看到采用data class可以简化Java Bean类。咱们的App采用了MVVM的架构,所以对应Model类所有使用data class。
使用Kotlin Android Extensions插件便可实现该功能,它是Kotlin 插件的组成之一,无需再单独安装插件。
咱们在各个modules的build.gradle中添加该插件,便可使用。
apply plugin: 'kotlin-android-extensions'
复制代码
布局文件中的id,能够直接在代码中使用。 首先,按照import kotlinx.android.synthetic.main.布局文件名*的方式导入。
例如MainActivity,它的布局文件是activity_main.xml 则按照以下的方式进行import
import kotlinx.android.synthetic.main.activity_main.*
复制代码
那么activity_main.xml中控件的id,能够直接在MainActivity中使用,无需使用findViewById 或者 butterknife。是否是特别方便?
App的埋点,使用本身家的产品--魔窗的sdk来作事件的埋点。
若是使用Java来开发App,可使用AOP来实现埋点。因为咱们的App采用Kotlin编写,Kotlin能够将事件的点击简化成以下的形式
view.setOnClickListener {
....
}
复制代码
这种简化了的lambda表达式,因此我仍是老老实实的使用传统方式进行埋点。
使用Kotlin的一般作法:
view.setOnClickListener {
TrackAgent.currentEvent().customEvent(eventName)
....
}
复制代码
或者
view.setOnClickListener {
TrackAgent.currentEvent().customEvent(eventName, trackMap)
....
}
复制代码
后来,我写了一个View的扩展函数click,后来通过同事的优化。能够查看简书的这篇文章 利用扩展函数优雅的实现“防止重复点击”
目前,已经将该扩展函数放入个人Kolin的工具类库 https://github.com/fengzhizi715/SAF-Kotlin-Utils
此时,埋点的代码变成这样
view.click {
TrackAgent.currentEvent().customEvent(eventName)
....
}
复制代码
或者
view.click {
TrackAgent.currentEvent().customEvent(eventName, trackMap)
....
}
复制代码
进一步的优化处理,对于View增长扩展函数clickWithTrack专门用于埋点的点击事件。
package cn.magicwindow.core.ext
import android.view.View
import cn.magicwindow.TrackAgent
import com.safframework.ext.clickWithTrigger
/** * * @FileName: * cn.magicwindow.core.ext.ViewExt.java * @author: Tony Shen * @date: 2018-04-24 17:17 * @version V1.0 <描述当前版本功能> */
fun <T : View> T.clickWithTrack(eventName: String, time: Long = 600, block: (T) -> Unit) = this.clickWithTrigger(time) {
TrackAgent.currentEvent().customEvent(eventName)
block(it as T)
}
fun <T : View> T.clickWithTrack(eventName: String, trackMap: HashMap<String, String>, time: Long = 600, block: (T) -> Unit) = this.clickWithTrigger(time) {
TrackAgent.currentEvent().customEvent(eventName, trackMap)
block(it as T)
}
复制代码
此时埋点能够这样使用:
view.clickWithTrack(key) {
....
}
复制代码
或者
view.clickWithTrack(key,trackMap) {
....
}
复制代码
Kotlin有不少的语法糖,使用这些语法糖能够简化代码以及更优雅地实现功能。
该系列的相关文章:
使用Kotlin高效地开发Android App(五)完结篇
Java与Android技术栈:每周更新推送原创技术文章,欢迎扫描下方的公众号二维码并关注,期待与您的共同成长和进步。