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!")
}
}
}
複製程式碼
- 我們不用再寫findviewbyid了!!!
- 不用像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物件,並初始化值(知道真相的我們,眼淚掉下來!) , 嘿嘿!接下來我們也效仿的來一套!
-
- 編寫自定義控制元件,CircleView
-
- 建立一個View.kt檔案
-
- 新增如下程式碼
inline fun ViewManager.circleView(init: com.yl.testcenter.CircleView.() -> Unit) = ankoView({ CircleView(it) }, theme = 0) { init() }
複製程式碼
ps: 其中ViewManager.circleView這個擴充套件方法名是在layout中控制元件使用的名稱
-
- 控制元件的裝逼使用
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()
}
}
複製程式碼
說明:
- 建立一個後臺協程任務,不開啟(start = CoroutineStart.LAZY宣告此協程不自定開啟,需要手動呼叫await才啟動)
- 建立一個UI協程任務,預設為開啟(沒有設定start=xxx)
- UI協程更新控制元件,根據後臺協程的返回值,協程不會阻塞UI執行緒。
與上面相比沒有執行緒切換的巢狀!