一.apply 函數(shù) 和 run 函數(shù)
1.1 apply函數(shù)
apply函數(shù)是指在函數(shù)塊內(nèi)可以通過 this 指代該對象切心,返回值為該對象自己鹏氧。在鏈式調(diào)用中渤涌,可以考慮使用它來不破壞鏈式。
/**
* 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
}
舉個例子:
/**
* 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)
}
}
執(zhí)行結果:
Hello World
Hello
第一個字符串是在閉包中打印的把还,第二個字符串是result的結果实蓬,它仍然是“Hello”。
1.2 run函數(shù)
run函數(shù)類似于apply函數(shù)吊履,但是run函數(shù)返回的是最后一行的值安皱。
/**
* 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)
}
}
執(zhí)行結果:
Hello World
Hello World
第一個字符串是在閉包中打印的,第二個字符串是result的結果艇炎,它返回的是閉包中最后一行的值酌伊,所以也打印“Hello World”。
1.3 項目中的使用
在App的反饋頁面中缀踪,需要輸入郵箱居砖、主題、內(nèi)容才能完成反饋按鈕的提交驴娃。
最初的寫法是這樣:
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函數(shù)
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函數(shù)一起使用
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
}
}
二.data class
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暇榴。
三.無需使用findViewById 或者 butterknife
使用Kotlin Android Extensions插件即可實現(xiàn)該功能厚棵,它是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的埋點,使用自己家的產(chǎn)品--魔窗的sdk來做事件的埋點炼杖。
如果使用Java來開發(fā)App灭返,可以使用AOP來實現(xiàn)埋點。由于我們的App采用Kotlin編寫坤邪,Kotlin可以將事件的點擊簡化成如下的形式
view.setOnClickListener {
....
}
這種簡化了的lambda表達式熙含,所以我還是老老實實的使用傳統(tǒng)方式進行埋點。
使用Kotlin的通常做法:
view.setOnClickListener {
TrackAgent.currentEvent().customEvent(eventName)
....
}
或者
view.setOnClickListener {
TrackAgent.currentEvent().customEvent(eventName, trackMap)
....
}
后來艇纺,我寫了一個View的擴展函數(shù)click怎静,后來經(jīng)過同事的優(yōu)化
目前,已經(jīng)將該擴展函數(shù)放入我的Kolin的工具類庫 https://github.com/fengzhizi715/SAF-Kotlin-Utils
此時黔衡,埋點的代碼變成這樣
view.click {
TrackAgent.currentEvent().customEvent(eventName)
....
}
或者
view.click {
TrackAgent.currentEvent().customEvent(eventName, trackMap)
....
}
進一步的優(yōu)化處理消约,對于View增加擴展函數(shù)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) {
....
}