【思貨】kotlin協程優雅的與Retrofit纏綿-kotlin DSL簡述

limuyang2發表於2019-06-08

這是一篇輔助文章,為了輔助大家理解後面的文章,先前先簡單的闡述下kotlin的DSL。

DSL是什麼

DSL指的是特定領域語言,利用kotlin的DSL語言,我們可以寫成更加整潔的程式碼,是程式碼的可閱讀行大幅度提升。基本的概念以及好處我就不再重複闡述了,網上已經有很多類似的文章了,我就通過具體的程式碼示例進行展示好了。

kotlin DSL程式碼長什麼樣

EditText

我還是從最常見EditTextTextWatcher說起。

Java中當我們需要新增文字輸入監聽的的時候,是如下的寫法:

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 ->

	}
}
複製程式碼

肯定有小夥伴,是這個表情:

https://user-gold-cdn.xitu.io/2019/6/8/16b3554d466d9837?w=360&h=360&f=jpeg&s=13317

那麼這是如何實現的呢,首先,自定義個類,繼承TextWatcher

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的引數方法內容(即:方法可以直接作為引數傳遞進),不懂自行百度,不再講解。

接下來,來實現一個DSL的擴充套件方法:

inline fun EditText.onTextChange(textWatcher: TextWatcherDsl.() -> Unit): TextWatcher {
    val watcher = TextWatcherDsl().apply(textWatcher)
    addTextChangedListener(watcher)
    return watcher
}
複製程式碼

ok,搞定了,所有的EditText都具有了onTextChange方法,監聽文字的方法需要什麼寫什麼。

  • 1、擴充套件方法不再具體解釋,不是本文重點

  • 2、這裡的inline是指內聯方法,即:在編譯時期,程式碼會直接插入掉用處,實際上不是呼叫外部方法。也就不會造成呼叫外部方法而導致的效能開銷,有興趣的小夥伴可以百度了學習。

這裡需要注意理解下引數TextWatcherDsl.() -> UnitTextWatcherDsl是我們剛剛自定義的類,然後後面跟了一個,就是說,這個引數可以接收TextWatcherDsl類裡的所有方法,只要是它裡面的方法都可以傳遞進來。

SharedPreferences

我們再來看下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")
}
複製程式碼

是不是簡單易讀。

https://user-gold-cdn.xitu.io/2019/6/8/16b3554dc9725c58?w=1141&h=640&f=jpeg&s=19829

我們來看下官方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

File

上面的寫法,會kotlin的小夥伴應該都見過了。接下來,我來展示下另一種DSL的寫法,可能你們會很少用。

這裡我操作File檔案的方法來展示。這裡我不再寫java程式碼。

常規寫法

首先我們看一下常規拷貝檔案的寫法:

fun copyTo(form:File, to: File) {
    // 具體操作檔案拷貝的程式碼
}
複製程式碼

使用:

copyTo(file1, file2)
複製程式碼

這種太常見了,Java裡也是如此操作的,不細說了。

kotlin擴充套件寫法

接下來改造下,寫成擴充套件方法:

fun File.copyTo(to: File) {
    // 具體操作檔案拷貝的程式碼
}
複製程式碼

使用:

file1.copyTo(file2)
複製程式碼

看起來好像舒服了那麼一點

終極寫法

infix fun File.copyTo(to: File) {
    // 具體操作檔案拷貝的程式碼
}
複製程式碼

使用:

file1 copyTo file2
複製程式碼

注意看擴充套件方法前面多了一個infix來修飾方法,是不是非常接近了我們人類說話時的語言方式。

你們的表情是這樣的:

https://user-gold-cdn.xitu.io/2019/6/8/16b3554dc6182fed?w=301&h=270&f=jpeg&s=7791

類似的方法,在anko庫中中也有很多地方使用,多去閱讀原始碼就會發現。

本次的簡介就到此為此,希望通過直接的程式碼展示,能讓各位找到些感覺

相關文章