Kotlin高阶函数的应用
高阶函数非常适用于简化各种API的调用,一些API原有用法在使用高阶函数进行简化后其可读性和易用性方面会有很大的提高。
1、简化SharedPreferences的使用
在简化前先来回顾下SharedPreferences的使用:
- 1、通过
Context.getSharedPreferences()
或Activity.getPreferences()
获取SharedPreferences
对象。 - 2、通过
SharedPreferences.edit()
获取SharedPreferences.Editor
对象 - 3、调用
Editor
的一系列putXX()
方法去保存数据 - 4、最后调用
Editor
的apply()
方法进行保存数据的提交
代码如下:
val sp = getPreferences(Context.MODE_PRIVATE)
val editor = sp.edit()
editor.apply {
putString("name", name)
putInt("age", age)
apply()
}
虽然API的使用虽然已经很简单但是我们依然可以使用高阶函数对其进行简化,首先创建一个SharedPreferences.kt
文件,然后在文件中定义save()
方法
inline fun SharedPreferences.save(block: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
editor.block()
editor.apply()
}
下面解释一下这个高阶函数:
- 1、首先通过
SharedPreferences.save()
定义了SharedPreferences
的一个扩展函数,这样我们就能通过SharedPreferences
对象调用save()
了,并且save()
就拥有了SharedPreferences
的上下文。 - 2、
save()
函数接收一个函数型的参数,SharedPreferences.Editor.()
表示这个函数类型参数是定义在SharedPreferences.Editor
中的,这个函数型的具体实现中就拥有了SharedPreferences.Editor
的上下文,并且需使用SharedPreferences.Editor
对象去调用block()
- 3、别忘记了将高阶函数声明为内联函数,减少额外的内存损耗
定义好了高阶函数save()
,下面看下具体的使用
getSharedPreferences("LoginActivity", Context.MODE_PRIVATE).save {
putString("name", "阿三")
putInt("age",19)
}
这里我们没有调用apply()
或commit()
,高阶函数内部已经调用了,是不是很简单啊。
最后不得不提一下Google中提供了KTX扩展库中包含了SharedPreferences的简化用法,我们在module的gradle中导入implementation 'androidx.core:core-ktx:1.3.1'
即可使用KTX扩展库了。下面看下KTX扩展库中对SharedPreferences的简化使用
getSharedPreferences("LoginActivity", Context.MODE_PRIVATE).edit {
putString("name", "阿三")
putInt("age", 19)
}
感兴趣的可以看下edit
的定义,和我们刚才定义的高阶函数基本是一样的。
2、简化ContentValue的使用
ContentValues的基本用法如下:
val contentValues = ContentValues()
contentValues. put("autor", "曹雪芹")
contentValues. put("price", 400)
contentValues. put("pages", 4000)
在真正开始简化之前,我们先来看下mapOf()
用法。
val map= mapOf(1 to "Apple",
2 to "Banana",
3 to "Orange")
可以看到使用1 to "Apple"
创建键值对,在Kotlin中使用A to B
语法结构会创建一个Pair对象,有了这个知识后我们创建一个ContentValues.kt
文件在文件中创建方法build()
方法,用于生成ContentValues
对象。
fun build(vararg pairs: Pair<String, Any?>): ContentValues {}
- 首先
build()
函数接收一个Pair
类型的参数,也就是使用A to B
生成Pair
对象。 - 参数前加了
vararg
关键字,表示build()
接收可变参数,类似于Java的public void test(String... strArray)
- 然后我们就能通过遍历
pairs
来向ContentValues
中添加数据,但是有个问题就是ContentValues
中的value
中不支持所有类型,所以只能通过when
类型判断进行添加数据,并且还是用了Kotlin的SmartCast功能,比如when语句进入Int类型后,value就自动被转换成了Int不再是Any类型。
fun build(vararg pair: Pair<String, Any?>): ContentValues {
val contentValues = ContentValues()
for (item in pair) {
val key = item.first
val value = item.second
when (value) {
is String -> contentValues.put(key, value)
is Long -> contentValues.put(key, value)
is Int -> contentValues.put(key, value)
is Double -> contentValues.put(key, value)
is ByteArray -> contentValues.put(key, value)
is Boolean -> contentValues.put(key, value)
is Float -> contentValues.put(key, value)
is Short -> contentValues.put(key, value)
is Byte -> contentValues.put(key, value)
null -> contentValues.putNull(key)
}
}
return contentValues
}
有了build
方法后,使用ContentValues就变得很简单了
val contentValues = build(
"autor" to "曹雪芹",
"price" to 400,
"pages" to 4000
)
这样我们就能通过类似mapOf()
方式来构建ContentValues
了,但是这和高阶函数没有任何关系,下面我们结合apply{}
来简化一下:
fun build(vararg pair: Pair<String, Any?>)=ContentValues().apply {
for (item in pair) {
val key = item.first
val value = item.second
when (value) {
is String -> put(key, value)
is Long -> put(key, value)
is Int -> put(key, value)
is Double -> put(key, value)
is ByteArray -> put(key, value)
is Boolean -> put(key, value)
is Float -> put(key, value)
is Short -> put(key, value)
is Byte -> put(key, value)
null -> putNull(key)
}
}
}
如果你很熟悉apply{}
的话,代码也很好理解,我们使用ContentValues()
对象调用apply
,ContentValues()
对象传入Lambda表达式中并作为其上下文,而且apply
的返回值就是调用者本身。其实KTX扩展库中也提供了类似方法contentValuesOf
来实现这个功能,感兴趣的可以自行实现。