Kotlin在Android上令人惊叹的技巧

发表于 4年以前  | 总阅读数:2277 次

Kotlin在Android上令人惊叹的技巧

我已经在这个Blog里讨论了很多Kotlin了,现在Google也正在讨论Kotlin,Kotlin 1.0 RC 已经发布了,毫无疑问,Kotlin不仅仅是Android的一个替代选择。Kotlin就在这里,我推荐你开始学习它。

在Android上我从哪里开始学习Kotlin?

这里已经有一些信息了,但是如果你想要真正的关注和快速学习,我推荐你这些资源:

  • Kotlin reference:如果你想深入了解这个语言的细节,这里是你能找到的最好的地方。我所知道关于这个语言的最好参考文献之一。

  • This blog:这个链接是我整理的所有关于Kotlin的文章的地方。你不应该错过它,文章属于初级和中级。

  • Kotlin for Android Developers, The book:如果你想快速和持续的学习,这本书是最好的方法。如果你已经了解了Andriod,这将是一个在你的项目中使用kotlin的快速途径。我已经编写很长一段时间了,当新版本发布的时候我就会更新它。已经更新到了Kotlin 1.0 RC。除此之外如果你订阅了这个列表,你将收到免费的头5个章节和这本书末尾显示的一个购买折扣

展示这个技巧

在我要讲解之前,有一个要说明的是Kotlin能给你带来简化的Android代码。这里有一组没有特定顺序的独立的例子。

简洁和趣味的编写点击监听事件

Java 7上编写监听和回调事件非常繁琐的原因是缺少了lambdas。Kotlin有非常好的lambdas和与Java库有非常好的兼容性。用lambda一个方法即可映射接口。你可以这么做:

myButton.setOnClickListener { navigateToDetail() }

这就是所有。

为什么layout要如此麻烦的inflate?再也不是了!

当你在Adapter中实例化时,你需要inflate一个layout,你会这样写:

LayoutInflater.from(parent.getContext()).inflate(R.id.my_layout, parent, false);

为什么父类不能inflate它自己的layout?好了,用Kotlin你可以。可以创建一个扩展的方法为你所用:

fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View {
    return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
}

ViewGroup现在有了一个新的inflate方法,接受参数是一个layout资源和可选的attachToRoot。通过传入不同的值,你可以创建同一个函数的很多不同版本,但不需要重载函数。现在可以这么做:

parent.inflate(R.layout.my_layout)
parent.inflate(R.layout.my_layout, true)

ImageView, 加载图片!

ImageView不能直接从网络上加载图片。我们有一些创建自定义view的库,比如:NetworkImageView,但这要求你使用继承,有时这会导致问题。现在我们知道我们可以在任何类上添加函数了,为什么不这样做呢?

fun ImageView.loadUrl(url: String) {
    Picasso.with(context).load(url).into(this)
}

现在你可以使用这个函数了,但神奇的是这个函数的本身。你现在有超级类ImageView

imageView.loadUrl("http://....")

很好。

令人厌恶的菜单switches...再也不了!

当重写onOptionsItemSelected时,我们通常创建一个设置好分支的switch,一般都返回true,最后都调用super。如果在这些action中有drawer设置,这是很糟糕的,因为你还要关闭这个drawer。一个可替代的方案(仅说明你能做什么,不是说这是最好的解决方案)是可以创建一个扩展的方法来做这些事情。

首先,我们创建一个consume方法,意思是处理了这个event(返回true),接收一个lambda做我们分支要做的工作。对于drawer也一样可以这么做。

override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
    R.id.action_settings -> consume { navigateToSettings() }
    R.id.nav_camera -> drawer.consume { navigateToCamera() }
    R.id.nav_gallery -> drawer.consume { loadGallery() }
    R.id.nav_slideshow -> drawer.consume { loadSlideshow() }
    else -> super.onOptionsItemSelected(item)
}

这些方法看起来是如何的?

inline fun consume(f: () -> Unit): Boolean {
    f()
    return true
}

对于drawer也类似:

inline fun DrawerLayout.consume(f: () -> Unit): Boolean {
    f()
    closeDrawers()
    return true
}

好消息是这些函数是内联的,意思是编译时这个方法会被方法的代码替代,所以在调用的地方编写代码是高效的。

Snacks和toasts很像… 但更不好用

这个代码显示了来自design support library的snack比toasts更不好用。但在Kotlin中我们可以做的更好。可以像下边这样写:

view.snack("This is my snack")
view.snack("This snack is short", Snackbar.LENGTH_SHORT) 

如果我们有一个action怎么办?别急,Kotlin这样解决:

view.snack("Snack message") {
    action("Action") { toast("Action clicked") }
}

我们可以为了被困扰任何事情创建小的DSLs。我们需要什么?

inline fun View.snack(message: String, length: Int = Snackbar.LENGTH_LONG, f: Snackbar.() -> Unit) {
    val snack = Snackbar.make(this, message, length)
    snack.f()
    snack.show()
}

第一个方法是创建snackbar,让这个snackbar之行我们提供的扩展方法,并显示自己。

这个方法会创建Snackbar action。这个action方法看起来是这样的:

fun Snackbar.action(action: String, color: Int? = null, listener: (View) -> Unit) {
    setAction(action, listener)
    color?.let { setActionTextColor(color) }
}

你甚至可以指定这个action的文字的颜色。如果你没有设置,默认值是null,最后一行代码决定如何做。你不喜欢最后一行代码?

color?.let { setActionTextColor(color) }

let内的代码只有color不为空的时候才会被执行。

现在我没有context...但谁关心呢?

在Java中,例如当我们查找一个view时,我们必须等到activity的布局文件加载完毕才能赋值给一个变量。

同样的也发生在context身上。如果一个object依赖context,你需要在class开始的地方声明它,然后在onCreate时候赋值。

用Kotlin委托,你仅需要委托一个值给lazy委托,当第一次被使用的时候才会执行:

override val toolbar by lazy { find<Toolbar>(R.id.toolbar) }
override val dataBase by lazy { DataBase(this) }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail)
    setSupportActionBar(toolbar)
    dataBase.loadWhatever()
}

find方法属于Anko库。但你可以更容易的做类似的事情:

inline fun <reified T : View> Activity.find(id: Int): T = findViewById(id) as T

更多的lambdas,更美丽

在Java中所有的事情都要创建对象。一个例子就是在创建一个完整的Runnable时的postDelayed。Kotlin的interoperability仅需要创建一个lambda,它的可读性好很多:

view.postDelayed({ doWhatever() }, 200)

如果你想创建一个线程并运行一些东西该怎么做呢?

Thread().run { 
    // Running in a thread    
}

“我恨AsyncTasks!!”。好了,那么就不用它们

感谢Anko库,我们有一个小的DSL来处理后台线程任务。

async() {
    // Do something in a secondary thread
    uiThread {
        // Back to the main thread
    }
}

它也是上下文感知的,所以如果它在antivity中被调用,如果activity关闭了,uiThread 也就不会被调用了。

为什么处理集合是如此的困难?不再是了

简单的回答就是缺少lambdas和功能操作。但Kotlin可以利用它们来工作,所以排序、转换、映射和过滤只是一个函数的调用。

return parsedContacts.filter { it.name != null && it.image != null }
        .sortedBy { it.name }
        .map { Contact(it.id, it.name!!, it.image!!) }

对于集合,你可以查看complete list of operations

操作重载:让你的想象力飞翔

谁说你不能像访问一个数组一样的访问ViewGroup中的view?这是不是很好?但一定很困难...当然不。你只需要用acts as an operator.创建一个扩展方法。

operator fun ViewGroup.get(pos: Int): View = getChildAt(pos)

现在你可以这样做:

val view = viewGroup[2]

你甚至可以创建一个返回view列表的扩展属性:

val ViewGroup.views: List<View>
    get() = (0 until childCount).map { getChildAt(it) }

现在你可以直接访问view:

val views = viewGroup.views

厌倦了这么多的getters, setters, toString(), equals()…?

Kotlin中的数据类给你提供了这些所有。

data class Person(val name: String, val surname: String, val age: Int) 

我们在这里做。

简单的方法启动activity

Anko也提供了一些好的方法可以不用创建intent、添加extras、调用方法...来启动另一个activity,所有的事情都可以用单独的一行代码做到:

startActivity<DetailActivity>("id" to 2, "name" to "Kotlin")

这回创建一个带有extras的intent,extras的值是该方法接收的一对列表参数值定义的。

Android扩展,或者如何忘记findViewById

使用Kotlin的Android扩展,仅需要添加一个专门的import,插件将会给activity、fragment甚至一个view创建一组参数设置,因此你不必担心去申明或找到这些view。参数的名称将在导入的XML文件中定义。例如,在RecyclerView adapter里,ViewHolder里你可以这么做:

import kotlinx.android.synthetic.main.item_contact.view.*

...

fun bindContact(contact: Contact) {
    itemView.name.text = contact.name
    itemView.avatar.loadUrl(contact.image)
    itemView.setOnClickListener { listener(contact) }
}

也可以更简洁。如果你多次使用同一个变量,你可以用标准库中的一些方法,例如apply

fun bindContact(contact: Contact) = itemView.apply {
    name.text = contact.name
    avatar.loadUrl(contact.image)
    setOnClickListener { listener(contact) }
}

这个东西太好了,太值了!

偷偷的看下Kotlin能为你做什么。很多事情仅是一个提高速度、帮助编写更清晰的代码,避免模版的语法糖果,最重要的是,让你感觉好像一个忍者。

Kotlin有许多你想学习的更惊叹的特性。这个语言真的是很有乐趣并富有创造力的,它注重实效(仅是一组不可思议的功能)并且完全集成了Android开发。

我推荐你去看一本,现在就获得他吧。

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:7月以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:7月以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:7月以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:7月以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:7月以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:7月以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:7月以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:7月以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:7月以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:7月以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:7月以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:7月以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:7月以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:7月以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:7月以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:7月以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:7月以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:7月以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:7月以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:7月以前  |  398次阅读  |  详细内容 »
 相关文章
简化Android的UI开发 4年以前  |  520719次阅读
Android 深色模式适配原理分析 3年以前  |  28663次阅读
Android阴影实现的几种方案 1年以前  |  10821次阅读
Android 样式系统 | 主题背景覆盖 3年以前  |  9611次阅读
 目录