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

相关文章
|
13天前
|
开发框架 小程序 前端开发
圈子社交app前端+后端源码,uniapp社交兴趣圈子开发,框架php圈子小程序安装搭建
本文介绍了圈子社交APP的源码获取、分析与定制,PHP实现的圈子框架设计及代码编写,以及圈子小程序的安装搭建。涵盖环境配置、数据库设计、前后端开发与接口对接等内容,确保平台的安全性、性能和功能完整性。通过详细指导,帮助开发者快速搭建稳定可靠的圈子社交平台。
120 18
|
13天前
|
存储 监控 API
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
|
9天前
|
JSON 供应链 搜索推荐
淘宝APP分类API接口:开发、运用与收益全解析
淘宝APP作为国内领先的购物平台,拥有丰富的商品资源和庞大的用户群体。分类API接口是实现商品分类管理、查询及个性化推荐的关键工具。通过开发和使用该接口,商家可以构建分类树、进行商品查询与搜索、提供个性化推荐,从而提高销售额、增加商品曝光、提升用户体验并降低运营成本。此外,它还能帮助拓展业务范围,满足用户的多样化需求,推动电商业务的发展和创新。
30 5
|
9天前
|
移动开发 安全 搜索推荐
圈子社交系统APP,同城本地圈子论坛开发,让身边的人沟通更加紧密
圈子社交系统APP是一款基于社交网络的移动应用,用户可创建、加入和管理兴趣圈子。主要功能包括:动态分享与交流、实时聊天、会员体系与身份认证、活动策划等。该APP注重个性化定制、社交关系深化、隐私安全及跨平台互联,提供丰富的社交体验。
|
12天前
鸿蒙语言开发 几十套鸿蒙ArkTs app毕业设计及课程作业
鸿蒙语言开发 几十套鸿蒙ArkTs app毕业设计及课程作业
19 1
|
18天前
|
前端开发 数据库 UED
uniapp开发,前后端分离的陪玩系统优势,陪玩app功能特点,线上聊天线下陪玩,只要4800
前后端分离的陪玩系统将前端(用户界面)和后端(服务器逻辑)分开开发,前者负责页面渲染与用户交互,后者处理数据并提供接口。该架构提高开发效率、优化用户体验、增强可扩展性和稳定性,降低维护成本,提升安全性。玩家可发布陪玩需求,陪玩人员发布服务信息,支持在线聊天、预约及线下陪玩功能,满足多样化需求。[演示链接](https://www.51duoke.cn/games/?id=7)
|
17天前
|
安全 算法 机器人
双重防护!红娘相亲app搭建开发,婚恋交友系统登录方式,密码+验证码的优势
在婚恋交友系统中,密码和验证码是两种重要的安全措施。密码用于验证用户身份,应设置为复杂组合以防止未经授权的访问;验证码则通过图形或字符识别,防止自动化攻击如暴力破解和注册机器人。两者同时开启可显著提高安全性,防止暴力破解和自动化注册,提升用户信任感。建议要求强密码、定期更新验证码样式,并在可疑登录时增加验证码复杂性。这样既能保障用户信息安全,又兼顾了用户体验。 ![交友11111.jpg](https://ucc.alicdn.com/pic/developer-ecology/hy2p6wcvgk4oe_c9eb8d6eb8144866b0cd1d96ffb0c907.jpg)
|
8月前
|
传感器 Android开发 开发者
构建高效Android应用:Kotlin的协程与Flow
【4月更文挑战第26天】随着移动应用开发的不断进步,开发者寻求更简洁高效的编码方式以应对复杂多变的业务需求。在众多技术方案中,Kotlin语言凭借其简洁性和强大的功能库逐渐成为Android开发的主流选择。特别是Kotlin的协程和Flow这两个特性,它们为处理异步任务和数据流提供了强大而灵活的工具。本文将深入探讨如何通过Kotlin协程和Flow来优化Android应用性能,实现更加流畅的用户体验,并展示在实际开发中的应用实例。
|
8月前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin与协程的完美融合
【2月更文挑战第25天】 在移动开发领域,性能优化和应用响应性的提升是永恒的追求。随着Android Jetpack组件库的不断丰富,Kotlin语言已经成为Android开发的首选。而Kotlin协程作为一种新的并发处理方案,它以轻量级线程的形式,为开发者提供了简洁高效的异步编程手段。本文将深入探讨Kotlin协程在Android应用中的实践运用,以及如何通过这种技术改善用户界面的流畅度和后台任务的处理能力,进而构建出更高效、更稳定的Android应用。
|
8月前
|
安全 Android开发 开发者
构建高效Android应用:Kotlin与协程的完美结合
【2月更文挑战第30天】在移动开发领域,性能优化和流畅的用户体验是关键。本文深入探讨了如何通过结合Kotlin语言和协程技术来提升Android应用的性能和响应能力。我们将分析Kotlin的优势,介绍协程的基本概念,并通过实际案例展示如何在应用中实现协程以简化异步编程,从而提供更加高效的解决方案。