超好用的官方core-ktx庫,瞭解一下(終)~

語言: CN / TW / HK

highlight: atelier-estuary-light theme: smartblue


本文是研究官方core-ktx庫的第五篇同樣也是最後一篇文章,旨在探究該庫中有哪些工具類或方法能夠提高我們的開發效率。

已更新的系列文章:

你需要了解的官方core-ktx庫能對開發帶來哪些便利?

官方core-ktx庫能對富文字Span開發帶來哪些便利?

官方core-ktx庫能對SparseArray系列、Pair開發帶來哪些便利?

超好用的官方core-ktx庫,瞭解一下~

Handler.postDelayed()簡化lambda傳入

不知道大家在使用Handler下的postDelayed()方法是不是感覺很不簡潔,我們看下這個函式原始碼: kotlin public final boolean postDelayed(@NonNull Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); }

可以看到Runnable型別的引數r放在第一位,在Kotlin中我們就無法利用其提供的簡潔的語法糖,只能這樣使用: kotlin private fun test11(handler: Handler) { handler.postDelayed({ //編寫程式碼邏輯 }, 100) }

有沒有感覺很彆扭,估計官方也發現了這個問題,就提供了這樣一個擴充套件方法: kotlin 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的語法糖就可以這樣使用:

```kotlin private fun test11(handler: Handler) { handler.postDelayed(200) {

}

} `` 可以看到這個函式型別使用了crossinline修飾,這個是用來加強內聯的,因為其另一個Runnable的函式型別中進行了呼叫,這樣我們就無法在這個函式型別action中使用return關鍵字了(return@標籤除外),避免使用return關鍵字帶來返回上的歧義不穩定性`。

除此之外,官方core-ktx還提供了類似的擴充套件方法postAtTime()方法,使用和上面一樣!!

Context.getSystemService()泛型實化獲取系統服務

看下以往我們怎麼獲取ClipboardManager: kotlin private fun test11() { val cm: ClipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager }

看下官方提供的方法:

kotlin public inline fun <reified T : Any> Context.getSystemService(): T? = ContextCompat.getSystemService(this, T::class.java)

藉助於內聯泛型實化簡化了獲取系統服務的程式碼邏輯: kotlin private fun test11() { val cm: ClipboardManager? = getSystemService() } 泛型實化的用處有很多應用場景,大家感興趣可以參考我另一篇文章:Gson序列化的TypeToken寫起來太麻煩?優化它

Context.withStyledAttributes簡化操作自定義屬性

這個擴充套件一般只有在自定義View中較常使用,比如讀取xml中設定的屬性值,先看下我們平常是如何使用的: ```kotlin 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`,這個一旦忘記寫就不好了,能讓程式保證的寫法那就儘量避免人為處理,所以官方提供了下面的擴充套件方法:kotlin public inline fun Context.withStyledAttributes( @StyleRes resourceId: Int, attrs: IntArray, block: TypedArray.() -> Unit ) { obtainStyledAttributes(resourceId, attrs).apply(block).recycle() } ```
使用如下:

kotlin 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進行寫操作時為了效率及安全保證需要開啟事務,一般我們都會手動進行開啟和關閉,還是那句老話,能程式自動保證的事情就儘量避免手動實現,所以一般我們都會封裝一個事務開啟和關閉的方法,如下:

kotlin private fun writeSQL(sql: String) { SQLiteDatabase.beginTransaction() //執行sql寫入語句 SQLiteDatabase.endTransaction() }

官方core-ktx也提供了相似的擴充套件方法: kotlin 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的方式,官方庫提供了下面的擴充套件方法簡化其建立流程:

kotlin 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) } } }

看下使用:

kotlin private fun createLRU() { lruCache<String, Bitmap>(3072, sizeOf = { _, value -> value.byteCount }, onEntryRemoved = { evicted: Boolean, key: String, oldValue: Bitmap, newValue: Bitmap? -> //快取物件被移除的回撥方法 }) }

可以看到,比之手動建立LruCache要稍微簡單些,能稍微節省下使用成本。

bundleOf()快捷寫入並建立Bundle物件

image.png

bundleOf()方法的引數被vararg宣告,代表一個可變的引數型別,引數具體的型別為Pair,這個物件我們之前的文章有講過,可以藉助中綴表示式函式to完成Pair的建立:

kotlin private fun test12() { val bundle = bundleOf("a" to "a", "b" to 10) }

這種通過傳入可變引數實現的Bundle如果大家不太喜歡,還可以考慮自行封裝通用擴充套件函式,在函式型別即lambda中實現更加靈活的Bundle建立及寫入:

1.自定義運算子過載方法set實現Bundle寫入:

```kotlin 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寫入多個值

```kotlin class BundleBuild(private val bundle: Bundle) {

infix fun String.to(that: Any?) {
    bundle[this] = that
}

} ```

其中to()方法使用了中綴表示式的寫法

3.暴漏擴充套件方法實現在lambda中完成Bundle的寫入和建立

kotlin private fun bundleOf(block: BundleBuild.() -> Unit): Bundle { return Bundle().apply { BundleBuild(this).apply(block) } }

然後就可以這樣使用: kotlin private fun test12() { val bundle = bundleOf { "a" to "haha" //經過一些邏輯操作獲取結果後在寫入Bundle val t1 = 10 * 5 val t2 = "" t2 to t1 } }

相比較於官方庫提供的bundleOf()提供的建立方式,通過函式型別也就是lambda建立並寫入Bundle的方式更加靈活,並內部支援執行操作邏輯獲取結果後再進行寫入。

總結

關於官方core-ktx的研究基本上已經七七八八了,總共輸出了五篇相關文章,對該庫瞭解能夠節省我們編寫模板程式碼的時間,提高開發效率,大家如果感覺寫的不錯,可以點個贊支援下哈,感謝!!

我正在參與掘金技術社群創作者簽約計劃招募活動,點選連結報名投稿