超好用的官方core-ktx库,了解一下(终)~
Handler.postDelayed()
简化lambda传入
不知道大家在使用Handler
下的postDelayed()
方法是不是感觉很不简洁,我们看下这个函数源码:
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
可以看到Runnable
类型的参数r
放在第一位,在Kotlin中我们就无法利用其提供的简洁的语法糖,只能这样使用:
private fun test11(handler: Handler) {
handler.postDelayed({
//编写代码逻辑
}, 100)
}
有没有感觉很别扭,估计官方也发现了这个问题,就提供了这样一个扩展方法:
public inline fun Handler.postDelayed(
delayInMillis: Long,
token: Any? = null,
crossinline action: () -> Unit
): Runnable {
val runnable = Runnable { action() }
if (token == null) {
postDelayed(runnable, delayInMillis)
} else {
HandlerCompat.postDelayed(this, runnable, token, delayInMillis)
}
return runnable
}
可以看到将函数类型(相当于上面的Runnable中的代码执行逻辑
)放到了方法参数的最后一位,这样利用kotlin的语法糖就可以这样使用:
private fun test11(handler: Handler) {
handler.postDelayed(200) {
}
}
可以看到这个函数类型使用了crossinline
修饰,这个是用来加强内联的,因为其另一个Runnable
的函数类型中进行了调用,这样我们就无法在这个函数类型action
中使用return
关键字了(return@标签
除外),避免使用return
关键字带来返回上的歧义不稳定性
。
除此之外,官方core-ktx
还提供了类似的扩展方法postAtTime()
方法,使用和上面一样!!
Context.getSystemService()
泛型实化获取系统服务
看下以往我们怎么获取ClipboardManager
:
private fun test11() {
val cm: ClipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
}
看下官方提供的方法:
public inline fun <reified T : Any> Context.getSystemService(): T? =
ContextCompat.getSystemService(this, T::class.java)
借助于内联
和泛型实化
简化了获取系统服务的代码逻辑:
private fun test11() {
val cm: ClipboardManager? = getSystemService()
}
泛型实化的用处有很多应用场景,大家感兴趣可以参考我另一篇文章:Gson序列化的TypeToken写起来太麻烦?优化它
Context.withStyledAttributes
简化操作自定义属性
这个扩展一般只有在自定义View
中较常使用,比如读取xml中设置的属性值,先看下我们平常是如何使用的:
private fun test11(
@NonNull context: Context,
@Nullable attrs: AttributeSet,
defStyleAttr: Int
) {
val ta = context.obtainStyledAttributes(
attrs, androidx.cardview.R.styleable.CardView, defStyleAttr,
androidx.cardview.R.style.CardView
)
//获取属性执行对应的操作逻辑
val tmp = ta.getColorStateList(androidx.cardview.R.styleable.CardView_cardBackgroundColor)
ta.recycle()
}
在获取完属性值后,还需要调用recycle()
方法回收TypeArray
,这个一旦忘记写就不好了,能让程序保证的写法那就尽量避免人为处理,所以官方提供了下面的扩展方法:
public inline fun Context.withStyledAttributes(
@StyleRes resourceId: Int,
attrs: IntArray,
block: TypedArray.() -> Unit
) {
obtainStyledAttributes(resourceId, attrs).apply(block).recycle()
}
使用如下:
private fun test11(
@NonNull context: Context,
@Nullable attrs: AttributeSet,
defStyleAttr: Int
) {
context.withStyledAttributes(
attrs, androidx.cardview.R.styleable.CardView, defStyleAttr,
androidx.cardview.R.style.CardView
) {
val tmp = getColorStateList(androidx.cardview.R.styleable.CardView_cardBackgroundColor)
}
}
上面的写法就保证了recycle()
不会漏写,并且带接收者的函数类型block: TypedArray.() -> Unit
也能让我们省略this
直接调用TypeArray
中的公共方法。
SQLiteDatabase.transaction()
自动开启事务读写数据库
平常对SQLite
进行写操作时为了效率及安全保证需要开启事务,一般我们都会手动进行开启和关闭,还是那句老话,能程序自动保证的事情就尽量避免手动实现,所以一般我们都会封装一个事务开启和关闭的方法,如下:
private fun writeSQL(sql: String) {
SQLiteDatabase.beginTransaction()
//执行sql写入语句
SQLiteDatabase.endTransaction()
}
官方core-ktx
也提供了相似的扩展方法:
public inline fun <T> SQLiteDatabase.transaction(
exclusive: Boolean = true,
body: SQLiteDatabase.() -> T
): T {
if (exclusive) {
beginTransaction()
} else {
beginTransactionNonExclusive()
}
try {
val result = body()
setTransactionSuccessful()
return result
} finally {
endTransaction()
}
}
大家可以自行选择使用!
<K : Any, V : Any> lruCache()
简化创建LruCache
LruCache
一般用作数据缓存,里面使用了LRU算法来优先淘汰那些近期最少使用的数据。在Android开发中,我们可以使用其设计一个Bitmap
缓存池,感兴趣的可以参考Glide内存缓存这块的源码,就利用了LruCache
实现。
相比较于原有创建LruCache
的方式,官方库提供了下面的扩展方法简化其创建流程:
inline fun <K : Any, V : Any> lruCache(
maxSize: Int,
crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 },
@Suppress("USELESS_CAST")
crossinline create: (key: K) -> V? = { null as V? },
crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit =
{ _, _, _, _ -> }
): LruCache<K, V> {
return object : LruCache<K, V>(maxSize) {
override fun sizeOf(key: K, value: V) = sizeOf(key, value)
override fun create(key: K) = create(key)
override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) {
onEntryRemoved(evicted, key, oldValue, newValue)
}
}
}
看下使用:
private fun createLRU() {
lruCache<String, Bitmap>(3072, sizeOf = { _, value ->
value.byteCount
}, onEntryRemoved = { evicted: Boolean, key: String, oldValue: Bitmap, newValue: Bitmap? ->
//缓存对象被移除的回调方法
})
}
可以看到,比之手动创建LruCache
要稍微简单些,能稍微节省下使用成本。
bundleOf()
快捷写入并创建Bundle对象
bundleOf()
方法的参数被vararg
声明,代表一个可变的参数类型,参数具体的类型为Pair
,这个对象我们之前的文章有讲过,可以借助中缀表达式函数to
完成Pair
的创建:
private fun test12() {
val bundle = bundleOf("a" to "a", "b" to 10)
}
这种通过传入可变参数实现的Bundle如果大家不太喜欢,还可以考虑自行封装通用扩展函数,在函数类型即lambda中实现更加灵活的Bundle创建及写入:
1.自定义运算符重载方法set
实现Bundle写入:
operator fun Bundle.set(key: String, value: Any?) {
when (value) {
null -> putString(key, null)
is Boolean -> putBoolean(key, value)
is Byte -> putByte(key, value)
is Char -> putChar(key, value)
is Double -> putDouble(key, value)
is Float -> putFloat(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Short -> putShort(key, value)
is Serializable -> putSerializable(key, value)
//其实数据类型自定参考bundleOf源码实现
}
}
2.自定义BundleBuild
支持向Bundle写入多个值
class BundleBuild(private val bundle: Bundle) {
infix fun String.to(that: Any?) {
bundle[this] = that
}
}
其中to()
方法使用了中缀表达式的写法
3.暴漏扩展方法实现在lambda中完成Bundle的写入和创建
private fun bundleOf(block: BundleBuild.() -> Unit): Bundle {
return Bundle().apply {
BundleBuild(this).apply(block)
}
}
然后就可以这样使用:
private fun test12() {
val bundle = bundleOf {
"a" to "haha"
//经过一些逻辑操作获取结果后在写入Bundle
val t1 = 10 * 5
val t2 = ""
t2 to t1
}
}
相比较于官方库提供的bundleOf()
提供的创建方式,通过函数类型也就是lambda创建并写入Bundle的方式更加灵活,并内部支持执行操作逻辑获取结果后再进行写入。
总结
关于官方core-ktx
的研究基本上已经七七八八了,总共输出了五篇相关文章,对该库了解能够节省我们编写模板代码的时间,提高开发效率,大家如果感觉写的不错,可以点个赞支持下哈,感谢!!
链接:https://juejin.cn/post/7124706297810780191
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。