這是一篇輔助文章,爲了輔助你們理解後面的文章,先前先簡單的闡述下kotlin的DSL。java
DSL指的是特定領域語言,利用kotlin的DSL語言,咱們能夠寫成更加整潔的代碼,是代碼的可閱讀行大幅度提高。基本的概念以及好處我就再也不重複闡述了,網上已經有不少相似的文章了,我就經過具體的代碼示例進行展現好了。bash
我仍是從最多見EditText
的TextWatcher
提及。app
在Java
中當咱們須要添加文本輸入監聽的的時候,是以下的寫法:ide
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
複製代碼
可是每每有時,咱們只須要afterTextChanged
監聽,並不須要其餘兩個,但因爲接口的限制,咱們不得不所有寫出將其實現。致使書寫體驗和閱讀體驗降低。性能
那麼在kotlin
中咱們能夠騷操做:學習
editText.onTextChange {
afterTextChanged { s ->
}
}
複製代碼
確定有小夥伴,是這個表情:ui
那麼這是如何實現的呢,首先,自定義個類,繼承TextWatcher
:spa
class TextWatcherDsl : TextWatcher {
private var afterTextChanged: ((s: Editable?) -> Unit)? = null
private var beforeTextChanged: ((s: CharSequence?, start: Int, count: Int, after: Int) -> Unit)? =
null
private var onTextChanged: ((s: CharSequence?, start: Int, before: Int, count: Int) -> Unit)? =
null
override fun afterTextChanged(s: Editable?) {
afterTextChanged?.invoke(s)
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
beforeTextChanged?.invoke(s, start, count, after)
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onTextChanged?.invoke(s, start, before, count)
}
fun afterTextChanged(after: (s: Editable?) -> Unit) {
afterTextChanged = after
}
fun beforeTextChanged(before: (s: CharSequence?, start: Int, count: Int, after: Int) -> Unit) {
beforeTextChanged = before
}
fun onTextChanged(onChanged: (s: CharSequence?, start: Int, before: Int, count: Int) -> Unit) {
onTextChanged = onChanged
}
}
複製代碼
這裏面涉及到kotlin
的參數方法內容(即:方法能夠直接做爲參數傳遞進),不懂自行百度,再也不講解。code
接下來,來實現一個DSL的擴展方法:orm
inline fun EditText.onTextChange(textWatcher: TextWatcherDsl.() -> Unit): TextWatcher {
val watcher = TextWatcherDsl().apply(textWatcher)
addTextChangedListener(watcher)
return watcher
}
複製代碼
ok,搞定了,全部的EditText
都具備了onTextChange
方法,監聽文本的方法須要什麼寫什麼。
一、擴展方法再也不具體解釋,不是本文重點
二、這裏的inline
是指內聯方法,即:在編譯時期,代碼會直接插入掉用處,實際上不是調用外部方法。也就不會形成調用外部方法而致使的性能開銷,有興趣的小夥伴能夠百度了學習。
這裏須要注意理解下參數TextWatcherDsl.() -> Unit
,TextWatcherDsl
是咱們剛剛自定義的類,而後後面跟了一個點
,就是說,這個參數能夠接收TextWatcherDsl
類裏的全部方法,只要是它裏面的方法均可以傳遞進來。
咱們再來看下Google官方對於SharedPreferences
的擴展。慣例,咱們Java
中使用SP寫入數據是這樣的:
SharedPreferences sp = getSharedPreferences("demo", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("key1", "value1");
editor.putString("key2", "value2");
editor.apply();
複製代碼
在kotlin
中是這樣的:
val sp = getSharedPreferences("demo", Context.MODE_PRIVATE)
sp.edit {
putString("key1", "value1")
putString("key2", "value2")
}
複製代碼
是否是簡單易讀。
咱們來看下官方Google是如何實現的這個方法:
inline fun SharedPreferences.edit( commit: Boolean = false, action: SharedPreferences.Editor.() -> Unit
) {
val editor = edit()
action(editor)
if (commit) {
editor.commit()
} else {
editor.apply()
}
}
複製代碼
是的,沒錯就這麼點。
參數SharedPreferences.Editor
後面跟了一個點
,能夠接受SharedPreferences.Editor
中的方法,例如putString
上面的寫法,會kotlin
的小夥伴應該都見過了。接下來,我來展現下另外一種DSL的寫法,可能大家會不多用。
這裏我操做File文件的方法來展現。這裏我再也不寫java代碼。
首先咱們看一下常規拷貝文件的寫法:
fun copyTo(form:File, to: File) {
// 具體操做文件拷貝的代碼
}
複製代碼
使用:
copyTo(file1, file2)
複製代碼
這種太常見了,Java裏也是如此操做的,不細說了。
接下來改造下,寫成擴展方法:
fun File.copyTo(to: File) {
// 具體操做文件拷貝的代碼
}
複製代碼
使用:
file1.copyTo(file2)
複製代碼
看起來好像舒服了那麼一點
infix fun File.copyTo(to: File) {
// 具體操做文件拷貝的代碼
}
複製代碼
使用:
file1 copyTo file2
複製代碼
注意看擴展方法前面多了一個infix
來修飾方法,是否是很是接近了咱們人類說話時的語言方式。
大家的表情是這樣的:
相似的方法,在anko
庫中中也有不少地方使用,多去閱讀源碼就會發現。
本次的簡介就到此爲此,但願經過直接的代碼展現,能讓各位找到些感受