高阶函数非常适用于简化各种API的调用,一些API的原有用法在使用高阶函数简化之后,不管是在易用性还是可读性方面,都可能会有很大的提升。
简化SharedPreferences的用法
之前学的最原始的向SharedPreferences中存储数据的代码如下:
//获取SharedPreferences.Editor对象
val editor = getSharedPreferences("data",Context.MODE_PRIVATE).edit()
editor.putString("name","ZLS") //添加String类型数据
editor.putInt("age",18)
editor.putBoolean("married",false)
editor.apply() //提交数据
但在红色箭头所指的扩展库中,添加了他的简化用法
它包含了一段类似于下面的代码,可以大大方便SharedPreferences的使用
fun SharedPreferences.edit(block: SharedPreferences.Editor.() -> Unit){
val editor = edit()
editor.block()
editor.apply()
}
通过扩展函数的方式向SharedPreferences
类中添加了一个edit
函数,并且它还接收一个函数类型的参数,因此edit
函数自然就是一个高阶函数了。 由于edit
函数内拥有SharedPreferences
的上下文,因此这里可以直接调用edit()
方法来获取SharedPreferences.Editor
对象。另外edit
函数接收的是一个SharedPreferences.Editor
的函数类型参数,因此这里需要调用editor.block()
对函数类型参数进行调用,我们就可以在函数类型参数的具体实现中添加数据了。最后还要调用editor.apply()
方法来提交数据,从而完成数据存储操作。
简化后使用代码如下:
getSharedPreferences("data",Context.MODE_PRIVATE).edit{
putString("name","ZLS")
putInt("age",18)
putBoolean("married",false)
}
简化ContentValues的用法
ContentValues
主要是用于结合SQLiteDatabase
的API存储和修改数据库中的数据,具体的基础用法如 下:
val values = ContentValues()
values.put("name", "Game of Thrones")
values.put("author", "George Martin")
values.put("pages", 720)
values.put("price", 20.85)
db.insert("Book", null, values)
下面介绍通过新建一个方法让其变得简单的用法:
首先新建⼀个ContentValues.kt
文件,然后在里面定义一个cvOf()
方法:
fun cvOf(vararg pairs: Pair<String, Any?>): ContentValues {
}
这个方法的作用是构建一个ContentValues
对象。
首先,cvOf()
方法接收了一个Pair
参数,也就是使用A to B
语法结构创建出来的参数类型,但是在参数前面加上了一个vararg
关键字,它对应的就是Java中的可变参数列表,允许向这个方法传入0个、1个、2个甚至任意多个Pair
类型的参数,这些参数都会被赋值到使用vararg
声明的这一个变量上面,然后使用for-in
循环可以将传入的所有参数遍历出来。
再来看声明的Pair
类型。由于Pair是一种键值对的数据结构,因此需要通过泛型来指定它的键和值分别对应什么类型的数据。ContentValues
的所有键都是字符串类型的,这里可以直接将Pair
键的泛型指定成String
。但ContentValues
的值却可以有多种类型(字符串型、整型、浮点型,甚至是null
),所以需要将Pair
值的泛型指定成Any?
。这是因为Any
是Kotlin中所有类的共同基类,相当于Java中的Object
,而Any?
则表示允许传入空值。
fun cvOf(vararg pairs: Pair<String, Any?>): ContentValues {
val cv = ContentValues()
for (pair in pairs) {
val key = pair.first
val value = pair.second
when (value) {
is Int -> cv.put(key, value)
is Long -> cv.put(key, value)
is Short -> cv.put(key, value)
is Float -> cv.put(key, value)
is Double -> cv.put(key, value)
is Boolean -> cv.put(key, value)
is String -> cv.put(key, value)
is Byte -> cv.put(key, value)
is ByteArray -> cv.put(key, value)
null -> cv.putNull(key)
}
}
return cv
}
when
语句进入Int
条件分支后,这个条件下面的value
会被自动转换成Int
类型,而不再是Any?
类型,这样就不需要像Java中那样再额外进行一次向下转型了, 这个功能在if
语句中也同样适用。
有了这个cvOf()
方法之后,使用ContentValues
时就会变得更加简单了,比如向数据库中插入一条数据就可以这样写:
val values = cvOf("name" to "Game of Thrones", "author" to "George Martin", "pages" to 720, "price" to 20.85)
db.insert("Book", null, values)
此外,还可以借助apply
函数进行二次优化
fun cvOf(vararg pairs: Pair<String, Any?>) = ContentValues().apply {
for (pair in pairs) {
val key = pair.first
val value = pair.second
when (value) {
is Int -> put(key, value)
is Long -> put(key, value)
is Short -> put(key, value)
is Float -> put(key, value)
is Double -> put(key, value)
is Boolean -> put(key, value)
is String -> put(key, value)
is Byte -> put(key, value)
is ByteArray -> put(key, value)
null -> putNull(key)
}
}
}
在上文提到的KTX库中也提供了一个具有同样功能的contentValuesOf()
方法,用法如下:
val values = contentValuesOf("name" to "Game of Thrones", "author" to "George Martin", "pages" to 720, "price" to 20.85)
db.insert("Book", null, values)
平时在编写代码的时候,直接使用KTX提供的contentValuesOf()
方法就可以了。