KTX – 更简洁的开发Android

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

介绍

如果你已经在使用 Kotlin 开发 Android 了,相信你深深的体会到了 Kotlin 的简洁、高效。不止如此,Google 为了让开发者更好的利用 Kotlin 语言能力(例如扩展函数/属性、lambda、命名参数和参数默认值),特意推出了 Android KTX,它是一组 Kotlin 扩展程序,可以以更简洁、更愉悦、更惯用的方式使用 Kotlin 进行 Android 开发。

使用

要将 KTX 加入到项目中,需要向 build.gradle 中添加依赖:

1dependencies {
2    // 目前最新版本为1.0.2
3    implementation 'androidx.core:core-ktx:1.0.2'
4}

这里附上官方和 GitHub 地址:
官方教程:https://developer.android.com/kotlin/ktx.html
GitHub:https://android.github.io/android-ktx/core-ktx/

目录

目前 KTX 已经包含了12个主目录(KTX1.0.2 版本):

目录名 包含的内容
animation 简化了动画监听事件的写法
content 包含了 contentvaluescontext 的扩展函数和 sp 的简化
database 包含了数据库游标的扩展函数和事务处理的简化
graphics 这里面包含的内容很多,主要用于自定义 View,如:PathPointCanvas等等
location Location 对象的解构,可写成 ( lat , lon ) = Location()
net 包含了 urifileString 相互转换
os bundleHandler 的简化写法
text 包含了 StringSpannableString 等等
transition 简化了对 transition 的监听操作
util 这个里面包含了一系列工具类,如:LruCachePairSizeRange 等等
view 包含了三块:ViewViewGroupMenu 三个类的多个方法
widget 这个组件中貌似专门为 EditTextaddTextChangedListener 准备的

实例

我们看看几个常见的用法,对比下在没有使用 KTX 和使用 KTX 后的变化

1) SP

 1val sp: SharedPreferences = getSharedPreferences("sp", Context.MODE_PRIVATE)
2// 常规
3val editor = sp.edit()
4editor.putString("name""taonce").apply()
5editor.putString("name""tao").apply()
6// KTX
7sp.edit {
8    putString("name""taonce")
9    putString("name""tao")
10}

这里就拿 SharePreferences.edit() 来看看 KTX 的实现,后面的很多大家请自行查看源码,大多都是采用了扩展函数和lambda 来实现的。

 1@SuppressLint("ApplySharedPref")
2inline fun SharedPreferences.edit(
3    // 标志是采用 commit 还是 apply
4    commit: Boolean = false,
5    // 这是一个Editor的扩展函数,采用lambda闭包
6    action: SharedPreferences.Editor.()
 -> Unit
7) {
8    // 获取editor对象
9    val editor = edit()
10    // 执行lambda
11    action(editor)
12    // 判断
13    if (commit) {
14        editor.commit()
15    } else {
16        editor.apply()
17    }
18}

2)获取系统服务

KTX 采用泛型来表明获取的服务类型,不需要再强转

1// context的扩展函数
2// 常规获取系统服务
3val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
4// KTX
5val windowManagerKT = getSystemService<WindowManager>()
6
7// 源码
8inline fun <reified T : Any> Context.getSystemService(): T? =
9        ContextCompat.getSystemService(this, T::class.java)

3)ContentValues

ContentValues 的操作上,则是用到了 apply() 操作符

 1// ContentValues
2// 常规
3val commonContentValues = ContentValues()
4commonContentValues.put("name""taonce")
5commonContentValues.put("age"20)
6// KTX
7val contentValues: ContentValues = contentValuesOf(
8    // 只需要传入键值对
9    Pair("name""taonce"),
10    "age" to 20
11)
12
13// 源码
14fun contentValuesOf(vararg pairs: Pair<String, Any?>) = ContentValues(pairs.size).apply {
15    for ((key, value) in pairs) {
16        when (value) {
17            null -> putNull(key)
18            is String -> put(key, value)
19            is Int -> put(key, value)
20            is Long -> put(key, value)
21            is Boolean -> put(key, value)
22            is Float -> put(key, value)
23            is Double -> put(key, value)
24            is ByteArray -> put(key, value)
25            is Byte -> put(key, value)
26            is Short -> put(key, value)
27            else -> {
28                val valueType = value.javaClass.canonicalName
29                throw IllegalArgumentException("Illegal value type $valueType for key "$key"")
30            }
31        }
32    }
33}

4)Animator动画

 1// Animator
2val animator = ObjectAnimator.ofFloat(tv, "alpha"1.0f, 0.2f)
3// 常规
4animator.addListener(object : Animator.AnimatorListener {
5    override fun onAnimationRepeat(animation: Animator?) {
6    }
7
8    override fun onAnimationEnd(animation: Animator?) {
9    }
10
11    override fun onAnimationCancel(animation: Animator?) {
12    }
13
14    override fun onAnimationStart(animation: Animator?) {
15    }
16})
17// KTX
18animator.doOnStart { }
19animator.doOnEnd {  }
20animator.doOnCancel {  }
21
22// 源码比较长,大家自行阅读,实现方式为:lambda + 参数的默认值

5)Handler

省去了让我们自己创建 Runnable 对象的操作

 1// 常规
2handler.postDelayed({
3    // runnable.run()
4}, 1000L)
5// KTX
6handler.postDelayed(1000L) {
7    // runnable.run()
8}
9
10// 源码
11inline fun Handler.postDelayed(
12    delayInMillis: Long,
13    token: Any? = null,
14    crossinline action: ()
 -> Unit
15): Runnable {
16    // 内部创建了Runnable,将lambda传入
17    val runnable = Runnable { action() }
18    if (token == null) {
19        postDelayed(runnable, delayInMillis)
20    } else {
21        HandlerCompat.postDelayed(this, runnable, token, delayInMillis)
22    }
23    return runnable
24}

6)LRUCache

KTX 在创建 LRUCache 帮助我们省去了繁琐的 object

 1// lruCache
2// 常规
3val commonLruCache = object : LruCache<String, Bitmap>(50) {
4    override fun sizeOf(key: String, value: Bitmap)Int {
5        return (value.rowBytes) * (value.height) / 1024
6    }
7}
8// KTX
9val lruCache: LruCache<String, Bitmap> = lruCache(50, sizeOf = { _, value ->
10    return@lruCache (value.rowBytes) * (value.height) / 1024
11})
12
13// 源码,还是结合lambda + 参数默认值实现
14inline fun <K : Any, V : Any> lruCache(
15    maxSize: Int,
16    crossinline sizeOf: (keyK, value: V)
 -> Int = { _, _ -> 1 },
17    @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946
18    crossinline create: (key: K) -> V? = { null as V? },
19    crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit =
20        { _, _, _, _ -> }
21): LruCache<K, V> {
22    return object : LruCache<K, V>(maxSize) {
23        override fun sizeOf(key: K, value: V) = sizeOf(key, value)
24        override fun create(key: K) = create(key)
25        override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) {
26            onEntryRemoved(evicted, key, oldValue, newValue)
27        }
28    }
29}

7)EditText

这部分和动画类似,专门处理 EditTextTextWatcher

 1// EditText
2val editText = EditText(this)
3// 常规 必须实现TextWatcher接口
4editText.addTextChangedListener(object : TextWatcher{
5    override fun afterTextChanged(s: Editable?) {
6    }
7
8    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
9    }
10
11    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
12    }
13})
14// KTX 可以实现某一个监听事件
15editText.doOnTextChanged { text, start, count, after ->
16    print("text is $text, start index is $start, text len is $count, changed index is $after")
17}
18editText.doAfterTextChanged {  }
19editText.doBeforeTextChanged { text, start, count, after ->  }
20
21// KTX源码自行分析哦,太长了

8)Location

最新说一个 Location,它的实现方式和上面都有所不同,采用了 Kotlin 的解构

1// Location
2val location = Location("")
3// 可将location解构成(lat,lon)
4val (lat, lon) = location
5
6// 源码
7inline operator fun Location.component1() = this.latitude
8inline operator fun Location.component2() = this.longitude

精力有限,举了常用的8个案例来说明 KTX,不过相信大家看完之后就完全明白了,哈哈。使用 KTX 在日常开发中还是蛮舒服的,结合 Kotlin 的语法糖,写出来的代码如牛奶般丝滑…

KTX 全部源码:https://android.github.io/android-ktx/core-ktx/

如果本文章你发现有不正确或者不足之处,欢迎你在下方留言或者扫描下方的二维码留言也可!

KTX - 更简洁的开发Android


原文始发于微信公众号(Taonce):KTX - 更简洁的开发Android