• 原文地址:5 Kotlin Extensions To Make Your Android Code More Expressive
  • 原文作者:Siva Ganesh Kantamani
  • 译文出自:翻译计划
  • 本文永久链接:github.com/xitu/gold-m…
  • 译者:keepmovingljzy
  • 校对者:PassionPenguin

5 个 Kotlin 扩展技巧让你的 Android 代码更具表现力

image.png
你或许现已看过一堆关于 Kotlin 扩展相关的文章了,但这篇文章不仅仅仅仅关于扩展。它是关于怎么让你的代码更具表现力,所以我专门解说并归纳我的顶级扩展,使代码尽或许天然一些。

本文的主要目的是学习怎么运用扩展,而不是复制代码片段,以自己的方法表达代码。

介绍

Kotlin 是一种现代的、富有表现力的言语,它是为开发人员而构建的。在我看来,好的 Kotlin 代码便是能够以天然、可读的方法表达自己的代码。

从 Java 转到 Kotlin 对我来说在很多方面都是一个巨大的转变,但我认为这在每个方面都是最好的。你能够参阅 我之前的文章。

我最喜欢 Kotlin 的一点是扩展。作为一名移动端 Java 开发人员,我从未想过向任何类增加自定义功用,尤其是向第三方库中的类增加自定义功用。但是当我听到扩展的概念时,着实让我大吃一惊。关于 Android 开发者来说,这个特性打开了大量代码增强的大门。

“Kotlin 供给了新功用扩展类的才能,而无需继承该类或运用类似装修器之类的规划形式。这是经过称为扩展的特别声明来完结。” — Kotlin 文档

假如你想学习更多 Kotlin 扩展相关知识,阅览这篇文章:运用 Kotlin 进行高档 Android 编程

我运用 Kotlin 扩展来使代码更具表现力,并使言语尽或许天然。

不要再拖了,开干!

1. 显现,隐藏,移除(视图)

移动开发人员的常见使命之一是隐藏和显现视图。假如你运用 Java,你需求调用 setVisibility 办法传入View.VISIBILEView.GONE 来完成。 如下:

view.setVisibility(View.GONE)

代码能够作业并且没有问题。但是运用 setget 办法让它看起来更蠢笨而不天然,Kotlin 供给了一种便当的方法来赋值,而不需求运用 setget 办法。现有代码如下:

view.visibility = View.GONE

即使现在,因为赋值操作符的存在,它看起来也不天然,所以我想,“为什么我不运用扩展来使它尽或许天然呢?”这时我开始运用以下扩展:

fun View.show(){
this.visibility = View.VISIBLE
}
fun View.hide() {
this.visibility = View.INVISIBLE
}
fun View.remove(){
this.visibility = View.GONE
}

现在你能够运用如下方法:

view.show()
view.hide()
view.remove()

现在看起来更友爱更天然。我很愿意优化它,所以假如你有任何主张,请留下谈论。

2. 校验

在任何开发环境中,验证字符串都是至关重要的。回到 2015 年,当我刚开始我的职业生涯,我看到一些应用程序显现null在一些文本字段中。这是因为没有适当的验证。

在运用 Kotlin 之前,我会保护一个实用工具类,并包括一些静态函数来验证字符串。看看 Java 中的一个简略验证函数:

// Function in utility class
public static Boolean isStringNotNullOrEmpty(String data){
return data != null && data.trim().length() > 0
&& !data.equalsIgnoreCase("null");
}
// Usage at call site
if(Utility.isStringNotNullOrEmpty(data))

从本质上讲数据类型不过是类。 因而咱们能够运用 Kotlin 扩展来增加验证功用。 例如,我创建了以下 Kotlin 扩展,其数据类型为 String,以查看其是否有用:

//Extension function
fun String?.valid() : Boolean =
this != null && !this.equals("null", true)
&& this.trim().isNotEmpty()
// Usage at call site
if(data.valid())

明显,data.valid() 看起来比 Utility.isStringNotNullOrEmpty(data) 更简练,可读性更好。调用数据类型上的扩展函数似乎比触发某些工具类函数更天然。下面是几个扩展,能够启发你编写自己的验证扩展:

//Email Validation
fun String.isValidEmail(): Boolean
= this.isNotEmpty() && Patterns.EMAIL_ADDRESS.matcher(this).matches()
//Phone number format
fun String.formatPhoneNumber(context: Context, region: String): String? {
val phoneNumberKit = PhoneNumberUtil.createInstance(context)
val number = phoneNumberKit.parse(this, region)
if (!phoneNumberKit.isValidNumber(number))
return null
return phoneNumberKit.format(number, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL)
}

3. 提取 Bundle 参数

在 Android 中,咱们经过捆绑一个键值对在组件之间传递数据。一般在从 bundle 中检索数据之前,咱们有必要查看一些东西。首要,咱们应该查看咱们正在寻觅的键是否在 bundle 中。然后咱们需求查看它是否有一个有用的值。一般做法如下:

fun extractData(extras : Bundle){
if (extras.containsKey("name") && extras.getString("name").valid()){
val name = extras.getString("name")
}
}

这涉及到更多的手写代码,坦率地说,它看起来并不美丽。幻想一下,假如有 5 个参数,代码看起来会有多庸俗。就像我说的,代码应该尽或许天然,并且需求最少的手动调用。

在这里,我运用了四个扩展函数:两个用于 Activity,两个用于 Fragment。相同,为每个组件供给一对,以获得一个非空值或一个可空值。如下:

// Activity related
inline fun <reified  T : Any> Activity.getValue(
lable : String, defaultvalue : T? = null) = lazy{
val value = intent?.extras?.get(lable)
if (value is T) value else defaultvalue
}
inline fun <reified  T : Any> Activity.getValueNonNull(
lable : String, defaultvalue : T? = null) = lazy{
val value = intent?.extras?.get(lable)
requireNotNull((if (value is T) value else defaultvalue)){lable}
}
// Fragment related
inline fun <reified T: Any> Fragment.getValue(lable: String, defaultvalue: T? = null) = lazy {
val value = arguments?.get(lable)
if (value is T) value else defaultvalue
}
inline fun <reified T: Any> Fragment.getValueNonNull(lable: String, defaultvalue: T? = null) = lazy {
val value = arguments?.get(lable)
requireNotNull(if (value is T) value else defaultvalue) { lable }
}

要了解内联函数和详细类型等高档特性,请参阅系列文章。

现在让咱们看看怎么运用上面的扩展:

val firstName by getValue<String>("firstName") // String?
val lastName by getValueNonNull<String>("lastName") // String

这种方法有三个长处:

  1. 简练,可读性好,代码量少。
  2. 空安全。
  3. 懒加载。

4. 资源扩展

在 Android 中,咱们需求经过资源类拜访项目资源。这涉及到一些每次需求从资源文件中检索数据时都需求手动编写的样板代码。假如没有任何扩展,检索 color 或 drawable 代码如下:

val color = ContextCompat.getColor(ApplicationCalss.instance, R.color.dark_blue)
val drawable = ContextCompat.getDrawable(MavrikApplication.instance, R.drawable.launcher)

当测验获取任何资源时,您需求经过生成的 R 文件中的资源 ID 拜访它。ID 的数据类型是Int。因而,咱们能够为每种资源类型编写 integer 类的扩展,并运用它们以削减样板代码增加可读性:

//Extensions
fun Int.asColor() = ContextCompat.getColor(ApplicationCalss.instance, this)
fun Int.asDrawable() = ContextCompat.getDrawable(MavrikApplication.instance, this)
//Usage at call site
val color = R.color.dark_blie.asColor()
val drawable = R.drawable.launcher.asDrawable()

5. 显现 Alert Dialog, Toast, or Snackbar

当涉及到前端开发时,不管运用哪种渠道,有时都需求向用户显现弹出框。或许是用于显现不重要的数据,或许弹出提示用户确定或许显现一些错误。

当你想要显现一个简略的弹出信息,你需求写的代码或许会很长。甚至不计划弹出对话框。这些都是常见的场景。它们应该简练且易于完成。这便是为什么我运用下面的扩展,使代码尽或许被简练的调用:

// Show alert dialog
fun Context.showAlertDialog(positiveButtonLable : String = getString(R.string.okay),
title : String = getString(R.string.app_name) , message : String,
actionOnPositveButton : () -> Unit) {
val builder = AlertDialog.Builder(this)
.setTitle(title)
.setMessage(message)
.setCancelable(false)
.setPositiveButton(positiveButtonLable) { dialog, id ->
dialog.cancel()
actionOnPositveButton()
}
val alert = builder.create()
alert?.show()
}
// Toash extensions
fun Context.showShotToast(message : String){
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
fun Context.showLongToast(message : String){
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
// Snackbar Extensions
fun View.showShotSnackbar(message : String){
Snackbar.make(this, message, Snackbar.LENGTH_SHORT).show()
}
fun View.showLongSnackbar(message : String){
Snackbar.make(this, message, Snackbar.LENGTH_LONG).show()
}
fun View.snackBarWithAction(message : String, actionlable : String,
block : () -> Unit){
Snackbar.make(this, message, Snackbar.LENGTH_LONG)
.setAction(actionlable) {
block()
}
}

编写这些扩展是一次性的作业。看看这些扩展的用法:

// To show an alert dialog in activities, fragments and more
showAlertDialog(message){
//TODO on user click on positive button on alert dialog
}
//To show toast in activities, fragments and more
showShotToast(message)
showLongToast(message)
//To show Snackbar applied on any active view
showShotSnackbar(message)
showLongSnackbar(message)
snackBarWithAction(message, lable){
//TODO on user click on snackbar action lable
}

常见的场景应该尽或许简单完成、可读性好和天然。

我期望你学到了一些有用的东西。感谢你的阅览。

假如发现译文存在错误或其他需求改进的当地,欢迎到 翻译计划 对译文进行修正并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。


翻译计划 是一个翻译优质互联网技术文章的社区,文章来历为 上的英文分享文章。内容掩盖 Android、iOS、前端、后端、区块链产品、规划、人工智能等领域,想要查看更多优质译文请继续关注 翻译计划、官方微博、知乎专栏。