介紹
如果你已經在使用 Kotlin 開發 Android 了,相信你深深的體會到了 Kotlin 的簡潔、高效。不止如此,Google 爲了讓開發者更好的利用 Kotlin 語言能力(例如擴展函數/屬性、lambda、命名參數和參數默認值),特意推出了 Android KTX,它是一組 Kotlin 擴展程序,可以以更簡潔、更愉悅、更慣用的方式使用 Kotlin 進行 Android 開發。
使用
要將 KTX 加入到項目中,需要向 build.gradle
中添加依賴:
dependencies {
// 目前最新版本爲1.0.2
implementation 'androidx.core:core-ktx:1.0.2'
}
這裏附上官方和 GitHub 地址:
官方教程
GitHub
目錄
目前 KTX 已經包含了12個主目錄(KTX1.0.2 版本):
目錄名 | 包含的內容 |
---|---|
animation | 簡化了動畫監聽事件的寫法 |
content | 包含了 contentvalues 、context 的擴展函數和 sp 的簡化 |
database | 包含了數據庫遊標的擴展函數和事務處理的簡化 |
graphics | 這裏麪包含的內容很多,主要用於自定義 View ,如:Path 、Point 、Canvas 等等 |
location |
對 Location 對象的解構,可寫成 ( lat , lon ) = Location() |
net | 包含了 uri 、file 和 String 相互轉換 |
os | 有 bundle 和 Handler 的簡化寫法 |
text | 包含了 String 、SpannableString 等等 |
transition | 簡化了對 transition 的監聽操作 |
util | 這個裏面包含了一系列工具類,如:LruCache 、Pair 、Size 和 Range 等等 |
view | 包含了三塊:View 、ViewGroup 和 Menu 三個類的多個方法 |
widget |
這個組件中貌似專門爲 EditText 的 addTextChangedListener 準備的 |
實例
我們看看幾個常見的用法,對比下在沒有使用 KTX 和使用 KTX 後的變化
1) SP
val sp: SharedPreferences = getSharedPreferences("sp", Context.MODE_PRIVATE)
// 常規
val editor = sp.edit()
editor.putString("name", "taonce").apply()
editor.putString("name", "tao").apply()
// KTX
sp.edit {
putString("name", "taonce")
putString("name", "tao")
}
這裏就拿 SharePreferences.edit()
來看看 KTX 的實現,後面的很多大家請自行查看源碼,大多都是採用了擴展函數和lambda
來實現的。
@SuppressLint("ApplySharedPref")
inline fun SharedPreferences.edit(
// 標誌是採用 commit 還是 apply
commit: Boolean = false,
// 這是一個Editor的擴展函數,採用lambda閉包
action: SharedPreferences.Editor.() -> Unit
) {
// 獲取editor對象
val editor = edit()
// 執行lambda
action(editor)
// 判斷
if (commit) {
editor.commit()
} else {
editor.apply()
}
}
2)獲取系統服務
KTX 採用泛型來表明獲取的服務類型,不需要再強轉
// context的擴展函數
// 常規獲取系統服務
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
// KTX
val windowManagerKT = getSystemService<WindowManager>()
// 源碼
inline fun <reified T : Any> Context.getSystemService(): T? =
ContextCompat.getSystemService(this, T::class.java)
3)ContentValues
在 ContentValues
的操作上,則是用到了 apply()
操作符
// ContentValues
// 常規
val commonContentValues = ContentValues()
commonContentValues.put("name", "taonce")
commonContentValues.put("age", 20)
// KTX
val contentValues: ContentValues = contentValuesOf(
// 只需要傳入鍵值對
Pair("name", "taonce"),
"age" to 20
)
// 源碼
fun contentValuesOf(vararg pairs: Pair<String, Any?>) = ContentValues(pairs.size).apply {
for ((key, value) in pairs) {
when (value) {
null -> putNull(key)
is String -> put(key, value)
is Int -> put(key, value)
is Long -> put(key, value)
is Boolean -> put(key, value)
is Float -> put(key, value)
is Double -> put(key, value)
is ByteArray -> put(key, value)
is Byte -> put(key, value)
is Short -> put(key, value)
else -> {
val valueType = value.javaClass.canonicalName
throw IllegalArgumentException("Illegal value type $valueType for key \"$key\"")
}
}
}
}
4)Animator動畫
// Animator
val animator = ObjectAnimator.ofFloat(tv, "alpha", 1.0f, 0.2f)
// 常規
animator.addListener(object : Animator.AnimatorListener {
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationEnd(animation: Animator?) {
}
override fun onAnimationCancel(animation: Animator?) {
}
override fun onAnimationStart(animation: Animator?) {
}
})
// KTX
animator.doOnStart { }
animator.doOnEnd { }
animator.doOnCancel { }
// 源碼比較長,大家自行閱讀,實現方式爲:lambda + 參數的默認值
5)Handler
省去了讓我們自己創建 Runnable
對象的操作
// 常規
handler.postDelayed({
// runnable.run()
}, 1000L)
// KTX
handler.postDelayed(1000L) {
// runnable.run()
}
// 源碼
inline fun Handler.postDelayed(
delayInMillis: Long,
token: Any? = null,
crossinline action: () -> Unit
): Runnable {
// 內部創建了Runnable,將lambda傳入
val runnable = Runnable { action() }
if (token == null) {
postDelayed(runnable, delayInMillis)
} else {
HandlerCompat.postDelayed(this, runnable, token, delayInMillis)
}
return runnable
}
6)LRUCache
KTX 在創建 LRUCache
幫助我們省去了繁瑣的 object
// lruCache
// 常規
val commonLruCache = object : LruCache<String, Bitmap>(50) {
override fun sizeOf(key: String, value: Bitmap): Int {
return (value.rowBytes) * (value.height) / 1024
}
}
// KTX
val lruCache: LruCache<String, Bitmap> = lruCache(50, sizeOf = { _, value ->
return@lruCache (value.rowBytes) * (value.height) / 1024
})
// 源碼,還是結合lambda + 參數默認值實現
inline fun <K : Any, V : Any> lruCache(
maxSize: Int,
crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 },
@Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946
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)
}
}
}
7)EditText
這部分和動畫類似,專門處理 EditText
的 TextWatcher
// EditText
val editText = EditText(this)
// 常規 必須實現TextWatcher接口
editText.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
// KTX 可以實現某一個監聽事件
editText.doOnTextChanged { text, start, count, after ->
print("text is $text, start index is $start, text len is $count, changed index is $after")
}
editText.doAfterTextChanged { }
editText.doBeforeTextChanged { text, start, count, after -> }
// KTX源碼自行分析哦,太長了
8)Location
最新說一個 Location
,它的實現方式和上面都有所不同,採用了 Kotlin 的解構
// Location
val location = Location("")
// 可將location解構成(lat,lon)
val (lat, lon) = location
// 源碼
inline operator fun Location.component1() = this.latitude
inline operator fun Location.component2() = this.longitude
精力有限,舉了常用的8個案例來說明 KTX,不過相信大家看完之後就完全明白了,哈哈。使用 KTX 在日常開發中還是蠻舒服的,結合 Kotlin 的語法糖,寫出來的代碼如牛奶般絲滑...
如果本文章你發現有不正確或者不足之處,歡迎你在下方留言或者掃描下方的二維碼留言也可!