Kotlin之UI篇

1004145468發表於2018-09-01

1.Android專案整合Kotlin

當我們的IDE安裝好Kotlin外掛(“Kotlin”)以後,專案想整合Kotlin將是一件非常輕鬆的事情,我們只需要在選單欄中選擇“Tools”->"Kotlin"->"Configure Kotin in Project"即可。

##2. Kotlin-android-extensions外掛減少模板程式碼

用java進行Android介面開發時,最多的模板程式碼findviewbyid(),於是我們專案中引入了ButterKnife進行編譯時註解。到了Kotlin的時候,我們需要寫的程式碼量就更少了,我們這樣做:

在app/build.gradle中加入kotlin-android-extensions外掛

apply plugin: 'kotlin-android-extensions'
複製程式碼

於是我們就可以這樣開發:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/btn_center"   //我才是重點
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />
</RelativeLayout>
複製程式碼
class VideoActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_video)
       btn_center.setOnClickListener{   // 我才是重點
            toast("be Clicked!")
        }
    }
}
複製程式碼
  1. 我們不用再寫findviewbyid了!!!
  2. 不用像butterknife那樣 @bindview(R.id.btn_center) Button centerBtn

對於控制元件我們只需要根據xml定義的ID直接使用!

3.通過Anko加快介面渲染效率

3.1 Anko的github地址

###3.2 AnKo的整合 ###3.3 佈局檔案的兩種方式的編寫(新增AnKo layout的依賴庫)

java中我們可以使用xml進行程式碼的編寫,直觀簡潔,但是效率不高,因為系統會進行xml解析生成對應的控制元件。當然,我們也可以直接用程式碼進行編寫,效率是提高了,但閱讀行和複雜性提高了。而Anko採用了一種這種的辦法,定義DSL語法,用程式碼編寫“xml”。

模式一:

class WebActivity : AppCompatActivity() {

    private lateinit var webview: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        verticalLayout {                                       // 重點在這裡
            button("open Link") {
                setOnClickListener {
                    getPagebyUrl("http://www.baidu.com")
                }
            }
            webview = webView().lparams(matchParent, matchParent)   //同時將建立的控制元件全域性化
        }
    }

                                                                  
    fun getPagebyUrl(url: String) {            // 此處後面會重點講解優化
        Thread {
            val Page = URL(url).readText()
            runOnUiThread {
                webview.loadData(Page, "text/html", "utf-8")
            }
        }.start()
    }
}
複製程式碼

擦!!這麼簡潔的佈局寫在這個類裡面還好,但是實際專案開發中,佈局就可能比較複雜了,一個xml動不動就上百來行,全寫著這個裡面,類不就很臃腫了麼?

小夥子(小妹妹)如果有這想法,證明思維還是蠻成熟,AnKo也考慮到這一點,支援Activity與layout分離,我們可以這樣:

模式二:

class MainActivityUI : AnkoComponent<MainActivity> {

    companion object {                    // 這裡定義了控制元件的ID,方面在Activity中根據ID找控制元件
        val req_btn = 1
        val showview = 2
    }

    override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
        verticalLayout {
            button("請求資料") {
                id = req_btn
            }.lparams(width = matchParent, height = wrapContent)
            textView {
                id = showview
            }.lparams(matchParent, matchParent)
        }
    }
}
複製程式碼

整合AnkoComponent 介面,在createView()方法中編寫DSL語法,建立佈局。

接下來我們看看Activity怎麼寫的?

class MainActivity : AppCompatActivity() {

    private lateinit var contentView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        MainActivityUI().setContentView(this)             //將上面的佈局設定給該Activity

        val reqBtn = find<Button>(MainActivityUI.req_btn)        // 根據ID尋找控制元件
        contentView = find<TextView>(MainActivityUI.showview)

        reqBtn.setOnClickListener {
            getPagebyUrl(“http://www.baidu.com”)
        }
    }

       fun getPagebyUrl(url: String) {            // 此處後面會重點講解優化
        Thread {
            val Page = URL(url).readText()
            runOnUiThread {
                contentView.text = Page
            }
        }.start()
    }
}
}
複製程式碼

###3.4 anko layout中新增自定義控制元件

上面的 MainActivityUI 中新增的都是系統自帶的控制元件,實際開發過程中,單純使用系統元件是遠遠不夠的,於是我們開始了自定義控制元件。那麼問題來了,自定義的控制元件如何新增到DSL的layout中,直接使用顯然是不能夠的! 不用擔心,我們先看一下anko是如何讓button支援DSL語法的(老規矩,點選剛剛編寫的button檢視原始碼)

inline fun ViewManager.button(text: CharSequence?): android.widget.Button {
    return ankoView(`$$Anko$Factories$Sdk25View`.BUTTON, theme = 0) {
        setText(text)
    }
}
複製程式碼

OMG,原來只是在ViewManager中新增一個擴充方法,通過ViewManager.ankoView()生成View物件,並初始化值(知道真相的我們,眼淚掉下來!) , 嘿嘿!接下來我們也效仿的來一套!

    1. 編寫自定義控制元件,CircleView
    1. 建立一個View.kt檔案
    1. 新增如下程式碼
  inline fun ViewManager.circleView(init: com.yl.testcenter.CircleView.() -> Unit) = ankoView({ CircleView(it) }, theme = 0) { init() }
複製程式碼

ps: 其中ViewManager.circleView這個擴充套件方法名是在layout中控制元件使用的名稱

    1. 控制元件的裝逼使用
verticalLayout {
            id = container
            button("請求資料") {
                id = req_btn
            }.lparams(width = matchParent, height = wrapContent)
            textView {
                id = showview
            }.lparams(matchParent, wrapContent)
            circleView {                                 //  ----  我在這!! 
                backgroundColor = Color.RED
            }
        }
複製程式碼

###3.5 非同步資料請求,更新UI(新增Kotlin coroutines依賴庫) 上面非同步請求網路資料的方式:

fun getPagebyUrl(url: String) {         
        Thread {
            val Page = URL(url).readText()
            runOnUiThread {
                contentView.text = Page
            }
        }.start()
複製程式碼

上面通過非同步執行緒切換UI執行緒更新控制元件,顯然程式碼變現上很直接了,但如果用協程就更加明瞭:

 fun getInfo() {
           
            var job = async(CommonPool,start = CoroutineStart.LAZY) {     //協程任務一
                getVideoInfo()  
            }
            launch(UI){                                                   //協程任務二
                contentView.text = job.await()
            }
        }
複製程式碼

說明:

  1. 建立一個後臺協程任務,不開啟(start = CoroutineStart.LAZY宣告此協程不自定開啟,需要手動呼叫await才啟動)
  2. 建立一個UI協程任務,預設為開啟(沒有設定start=xxx)
  3. UI協程更新控制元件,根據後臺協程的返回值,協程不會阻塞UI執行緒。

與上面相比沒有執行緒切換的巢狀!

1. Kotlin學習入門文件 2. 協程相關知識 3. 深入瞭解協程與channel的關係 4. 相關框架與事例

相關文章