美文网首页KotlinKotlin
Kotlin 真香系列:扩展函数和属性

Kotlin 真香系列:扩展函数和属性

作者: 孙强Jimmy | 来源:发表于2020-05-28 09:36 被阅读0次

本文将介绍 Kotlin 中的扩展函数和扩展属性,并用这两个特性来逐步优化代码的写法,希望大家学习这种特性并在实践当中做更多的扩展。

在 Android 开发中,大家可能经常使用这样的代码来判断或设置视图的可见性:

if (view.getVisibility() == View.VISIBLE) {
    view.setVisibility(View.GONE);
    // ...
}

或者封装了一个 px 转 dp 的工具类,如果计算逻辑比较复杂,可能会写成这样:

int width = (textView.getWidth() + DisplayUtils.dp2px(40)) / 2 - DisplayUtils.dp2px(18);

如果在一行代码中 DisplayUtils.dp2px() 工具类使用非常多的话代码会很长,也会增加理解难度。

那么,如果使用 Kotlin 中的扩展函数或扩展属性去精简一下,就可以方便很多。下面来介绍一下。

1. 扩展函数

所谓扩展函数,就是对一个现有类扩展定义一个成员函数,不过该定义在类的外面。一般我们如果想对一个类封装一个 API 方法,但又不能直接修改该类时,就可以用到扩展函数。

扩展方法的一般格式如下:

fun 类名.方法名([参数 1, 参数 2, ...]): 返回类型 {
    方法体
}

下面,我们将判断或设置视图的可见性封装成扩展方法,并定义在一个 kt 文件的最外层:

// ViewExtensions.kt
fun View.isVisible(): Boolean {
    return visibility == View.VISIBLE
}

fun View.setVisible(visible: Boolean) {
    visibility = if (visible) View.VISIBLE else View.GONE
}

在扩展方法中,可以使用这个类的公有的方法和属性,例如上面代码中的 getVisibility()setVisibility()

之后,在 Kotlin 代码中所有的 View 类及它的子类都可以用这两个方法了:

if (view.isVisible()) {
    view.setVisible(false)
    // ...
}

下面我们来看看扩展方法转换成 Java 代码是什么样的:

public final class ViewExtensionsKt {
   public static final boolean isVisible(@NotNull View $this$isVisible) {
      Intrinsics.checkParameterIsNotNull($this$isVisible, "$this$isVisible");
      return $this$isVisible.getVisibility() == 0;
   }

   public static final void setVisible(@NotNull View $this$setVisible, boolean visible) {
      Intrinsics.checkParameterIsNotNull($this$setVisible, "$this$setVisible");
      $this$setVisible.setVisibility(visible ? 0 : 8);
   }
}

可以看出来转成 Java 代码后,将这个要扩展的类换成静态方法的第一个参数了,而原扩展方法的参数列表变成了从第二个参数开始定义,因此,我们可以按如下方式在 Java 中使用该扩展方法:

if (ViewExtensionsKt.isVisible(view)) {
    ViewExtensionsKt.setVisible(view, false);
}

至于怎么查看 Kotlin 转成的 Java 代码,方法如下:

  1. 在 Android Studio 顶部菜单中找到 Tools → Kotlin → Show Kotlin Bytecode
  2. 在右侧的 Kotlin Bytecode 窗口中点击 Decompile 按钮,就可以看到对应的 Java 代码了。

这里还有个小技巧,如果大家不喜欢 Kotlin 文件转成 Java 后默认的类的名字(例如上面的 ViewExtensionsKt),我们还可以自定义要转成 Java 的类名。

例如,在上例中的 ViewExtensions.kt 文件的顶部添加一行如下代码:

@file: JvmName("ViewUtils")

这样转成 Java 的类名就是 ViewUtils 了,如下:

public final class ViewUtils {
   public static final boolean isVisible(@NotNull View $this$isVisible) {
      Intrinsics.checkParameterIsNotNull($this$isVisible, "$this$isVisible");
      return $this$isVisible.getVisibility() == 0;
   }

   public static final void setVisible(@NotNull View $this$setVisible, boolean visible) {
      Intrinsics.checkParameterIsNotNull($this$setVisible, "$this$setVisible");
      $this$setVisible.setVisibility(visible ? 0 : 8);
   }
}

2. 扩展属性

Kotlin 除了可以扩展函数,还可以扩展属性。但是这个属性并不会保存在对象里,所以我们使用它时需要实现 getter 函数,如果是可变对象,则还要实现 setter 函数。格式如下:

val 类名.属性名: 类型
    get() {
        方法体
    }

var 类名.属性名: 类型
    get() {
        方法体
    }
    set(value) {
        方法体
    }

下面,为视图扩展一个属性来判断其可见性:

val View.isVisible: Boolean
    get() {
        return visibility == View.VISIBLE
    }

在 Kotlin 中,当方法体内只有一条 return 语句时是可以简写的,如下:

val View.isVisible get() = visibility == View.VISIBLE

接着,将该属性改为 var,重写 setter 方法来设置可见性:

var View.isVisible
    get() = visibility == View.VISIBLE
    set(value) {
        visibility = if (value) View.VISIBLE else View.GONE
    }

这样,在 Kotlin 中就可以这么使用了:

if (view.isVisible) {
    view.isVisible = false
    // ...
}

我们再来看看扩展属性的定义转成 Java 代码是什么样子的:

public final class ViewUtils {
   public static final boolean isVisible(@NotNull View $this$isVisible) {
      Intrinsics.checkParameterIsNotNull($this$isVisible, "$this$isVisible");
      return $this$isVisible.getVisibility() == 0;
   }

   public static final void setVisible(@NotNull View $this$isVisible, boolean value) {
      Intrinsics.checkParameterIsNotNull($this$isVisible, "$this$isVisible");
      $this$isVisible.setVisibility(value ? 0 : 8);
   }
}

大家可以看到,扩展属性和扩展方法转成的 Java 代码是一样的,因此在 Java 中使用的时候也是一样的。

最后再说个 dp 转 px 的例子,我们可以对 Number 类扩展一个属性,代码如下:

val Number.dp get() = round(toFloat() * Resources.getSystem().displayMetrics.density).toInt()

这样我们就可以直接使用 18.dp0.5.dp 这种形式将一个数字转成对应的 dp 大小,是不是很简洁?

3. Kotlin 扩展库

其实,Google 官方已经为我们扩展了很多实用的函数和属性,比如 https://developer.android.com/kotlin/ktx

大家有兴趣的可以去引入一下慢慢探索~

参考

相关文章

  • Kotlin 真香系列:扩展函数和属性

    本文将介绍 Kotlin 中的扩展函数和扩展属性,并用这两个特性来逐步优化代码的写法,希望大家学习这种特性并在实践...

  • 浅谈Kotlin语法篇之扩展函数(五)

    1、为什么要使用Kotlin中的扩展函数? 2、怎么去使用扩展函数和扩展属性? 3、什么是扩展函数和属性? 4、扩...

  • Kotlin入门(五):扩展属性,函数(笔记)

    Kotlin中可以扩展原始类型的函数和属性,原始类型称为“接受类型”. 扩展函数 在接收类型上添加扩展函数,语法如...

  • Kotlin扩展函数和扩展属性

    Kotlin 可以对一个类的属性和方法进行扩展,对被扩展的类代码本身不会造成任何影响。 扩展函数可以为已经存在的类...

  • Kotlin 扩展函数和扩展属性

      Kotlin 能够扩展一个类的新功能而无需继承该类或者使用像装饰者这样的设计模式。 这通过叫做 扩展 的特殊声...

  • Kotlin函数扩展和属性扩展

    一、前言: 我们都知道java要扩展一个已有类的方法和属性必须采用继承、组合或直接修改现有类来进行功能和属性的扩展...

  • kotlin中扩展属性和扩展函数

    一、kotlin扩展属性扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。初始化属性因为属性没有后端...

  • Kotlin扩展函数和属性

     在Kotlin中,为什么会有扩展?因为可以让使用者(或定义者)不修改即有源代码的情况下,同时又不借助于装饰模式等...

  • kotlin Reified 理解

    参考 Reified讲解 优缺点 代码理解 使用kotlin的扩展函数和扩展属性为Activity扩展出一个sta...

  • Kotlin扩展函数和扩展属性笔记

    1. 扩展函数 Kotlin的扩展函数可以让你作为一个类成员进行调用的函数,但是是定义在这个类的外部。这样可以很方...

网友评论

    本文标题:Kotlin 真香系列:扩展函数和属性

    本文链接:https://www.haomeiwen.com/subject/piegahtx.html