使用Kotlin高效地開發Android App(二)

Tony沈哲發表於2018-04-27
旋轉的樓梯.jpg

上一篇文章介紹了專案中所使用的Kotlin特性,本文繼續整理當前專案所用到的特性。

一.apply 函式 和 run 函式

with、apply、run函式都是Kotlin標準庫中的函式。with在第一篇文章中已經介紹過。

1.1 apply函式

apply函式是指在函式塊內可以通過 this 指代該物件,返回值為該物件自己。在鏈式呼叫中,可以考慮使用它來不破壞鏈式。

/** * Calls the specified function [block] with `this` value as its receiver and returns `this` value. */@kotlin.internal.InlineOnlypublic 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)
}
}複製程式碼

執行結果:

Hello WorldHello複製程式碼

第一個字串是在閉包中列印的,第二個字串是result的結果,它仍然是“Hello”。

1.2 run函式

run函式類似於apply函式,但是run函式返回的是最後一行的值。

/** * Calls the specified function [block] with `this` value as its receiver and returns its result. */@kotlin.internal.InlineOnlypublic 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 WorldHello World複製程式碼

第一個字串是在閉包中列印的,第二個字串是result的結果,它返回的是閉包中最後一行的值,所以也列印“Hello World”。

1.3 專案中的使用

在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
}
}複製程式碼

二.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外掛即可實現該功能,它是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.extimport android.view.Viewimport cn.magicwindow.TrackAgentimport 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(五)完結篇

使用Kotlin高效地開發Android App(四)

使用Kotlin高效地開發Android App(三)

使用Kotlin高效地開發Android App(一)


Java與Android技術棧:每週更新推送原創技術文章,歡迎掃描下方的公眾號二維碼並關注,期待與您的共同成長和進步。

使用Kotlin高效地開發Android App(二)

來源:https://juejin.im/post/5ae31d85518825671c0e4b83

相關文章