使用Kotlin高效地开发Android App(二)

简介: 使用Kotlin高效地开发Android App(二)

上一篇文章介绍了项目中所使用的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.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)
    }
}


执行结果:

Hello World
Hello


第一个字符串是在闭包中打印的,第二个字符串是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.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”。


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.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有很多的语法糖,使用这些语法糖可以简化代码以及更优雅地实现功能。

相关文章
|
8月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1459 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
8月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1045 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
8月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1125 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
9月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
886 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
8月前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
396 0
|
9月前
|
Java 开发工具 Maven
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
1202 6
|
11月前
|
移动开发 Java 编译器
Kotlin与Jetpack Compose:Android开发生态的演进与架构思考
本文从资深Android工程师视角深入分析Kotlin与Jetpack Compose在Android系统中的技术定位。Kotlin通过空安全、协程等特性解决了Java在移动开发中的痛点,成为Android官方首选语言。Jetpack Compose则引入声明式UI范式,通过重组机制实现高效UI更新。两者结合不仅提升开发效率,更为跨平台战略和现代架构模式提供技术基础,代表了Android开发生态的根本性演进。
450 0
app开发的一些思路
<p><br></p> <p><br></p> <p></p> <h3 style="margin:0px; padding:0px; border:0px; vertical-align:baseline; clear:both; font-weight:normal; list-style:none; color:rgb(102,102,102); font-family:宋体;
3320 0
x3d
小型app开发的思路
前提: 1. 性能不是最重要; 2. 人手少; 3. 速度要快;   结论: 1. 混合式 2. 减少app的复杂程度 3. 追求性能   (博客,尽量让自己每天写一点,短一点都可以)
x3d
690 0
|
8月前
|
缓存 移动开发 JavaScript
如何优化UniApp开发的App的启动速度?
如何优化UniApp开发的App的启动速度?
1374 139