用Kotlin的Anko庫優雅開發Android應用--Anko庫詳細教程

前言

最近Kotlin的呼聲又是日益高漲,前幾天9012年Google IO正式將Kotlin從first _class提高爲kotlin_first。我也是接觸了一段時間的Kotlin,給個人感受就是簡約,快速。無需繁瑣的findId,高階函數的應用,再加上Kotlin的null 安全,更是將代碼的崩潰率降到更低。html

今天咱們就來介紹一下今天的主角---Ankojava

1.Anko

Anko是JetBrains開發的一個強大的庫,提及JetBrains ,那就牛逼了,Kotlin語言是他們開發的,最流行的的開發工具intellij idea都是他們開發的,AS也是基於IDEA的。好了,言歸正傳,Anko是Kotlin官方開發的一個讓開發Android應用更快速更簡單的Kotlin庫,而且能讓咱們書寫的代碼更簡單清楚更容易閱讀。它包括多個部分react

  1. Anko Commons: a lightweight library full of helpers for intents, dialogs, logging and so on;
  2. Anko Layouts: a fast and type-safe way to write dynamic Android layouts;
  3. Anko SQLite: a query DSL and parser collection for Android SQLite;
  4. Anko Coroutines: utilities based on the kotlinx.coroutines library.

1.1 如何使用

添加依賴android

dependencies {
    implementation "org.jetbrains.anko:anko:$anko_version"
}
複製代碼

這裏麪包括上面四個部分,固然你也能夠只依賴一個部分,以下:sql

dependencies {
    // Anko Commons
    implementation "org.jetbrains.anko:anko-commons:$anko_version"

    // Anko Layouts
    implementation "org.jetbrains.anko:anko-sdk25:$anko_version" // sdk15, sdk19, sdk21, sdk23 are also available
    implementation "org.jetbrains.anko:anko-appcompat-v7:$anko_version"

    // Coroutine listeners for Anko Layouts
    implementation "org.jetbrains.anko:anko-sdk25-coroutines:$anko_version"
    implementation "org.jetbrains.anko:anko-appcompat-v7-coroutines:$anko_version"

    // Anko SQLite
    implementation "org.jetbrains.anko:anko-sqlite:$anko_version"
}
複製代碼

下面咱們分別介紹這幾個功能。數據庫

2 AnkoCommons

AnkoCommons對Android開發者來講是一個工具集,包括但不限於下面這幾個數組

  1. Intents
  2. Dialogs and toasts
  3. Logging
  4. Resources and dimensions

2.1 Intents

前面已經提到,Commons 庫是一個工具集,那Intents主要是幫助簡化Activity之間的跳轉。安全

傳統的 Kotlin 啓動新的 Activity 的方式是建立一個 Intent,同時可能傳遞一些參數,最後將建立的 Intent 經過 Context 的 startActivity() 方法傳遞,就像這樣:bash

val intent = Intent(this, SomeOtherActivity::class.java)
intent.putExtra("id", 5)
intent.setFlag(Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)
複製代碼

然鵝你用Anko只須要這樣:app

startActivity(intentFor("id" to 5).singleTop())

若是想要傳遞多個參數,你也能夠這樣

startActivity<SomeOtherActivity>(
    "id" to 5,
    "city" to "Denpasar"
)
複製代碼

固然還有一些關於Intent的其它操做,如:撥打電話等:以下

在這裏插入圖片描述

2.2 Dialogs and toasts

這個庫主要是用來快速搭建Dialog和toast,具體包含如下幾個

  • Toast
  • SnackBar
  • Alert (Dialog)
  • Selectors
  • Progress dialogs

2.2.1 Toast

Anko爲咱們提供了更加簡單的Toast使用,只須要一行代碼便可實現

toast("Hi there!")
toast(R.string.message)
longToast("Wow, such duration")
複製代碼

2.2.2 SnackBars

SnackBar是 Android Support Library 22.2.0 裏面新增提供的一個控件,咱們能夠簡單的把它理解成一個增強版的Toast,或者是一個輕量級的Dialog。 咱們能夠用下面代碼快速建立snackbar。

view.snackbar("Hi there!")
view.snackbar(R.string.message)
view.longSnackbar("Wow, such duration")
view.snackbar("Action, reaction", "Click me!") { doStuff() }
複製代碼

這裏須要傳入view對象,這個能夠是佈局中的任意一個view對象。

2.2.3 Alerts

Anko Alerts主要包括如下幾個功能:

  1. Android 默認dialog
  2. Android Appcompat 中AlertDialog
  3. 自定義Dialog

1.Android 默認dialog 經過如下代碼就能夠構建一個能夠交互的Android 默認dialog。

alert("Hi, I'm Roy", "Have you tried turning it off and on again?") {
    yesButton { toast("Oh…") }
    noButton {}
}.show()
複製代碼

代碼比較簡單,就不作解釋。

2.Android Appcompat 中AlertDialog 另外Anko還提供了Appcompat的AlertDialog實現方式,以下:

alert(Appcompat, "Some text message").show()
複製代碼

3.自定義Dialog 什麼,不能自定義dialog嗎?怎麼會,自定義dialog也是很是的簡單

alert {
    customView {
        editText()
    }
}.show()
複製代碼

2.2.4 Selectors (包含列表的Dialog)

咱們平時建立列表Dialog是這樣的:

val listItems = arrayOf("Russia", "USA", "Japan", "Australia")  //傳數組
        val listDialog: AlertDialog.Builder = AlertDialog.Builder(this)
        listDialog.setItems(listItems) { p0, p1 ->
        	toast(p1)
        }
        val dialog: AlertDialog = listDialog.create()
        dialog.show()
        val window: Window = dialog.window
        val params: WindowManager.LayoutParams = window.attributes
        params.y = 45 * ScreenUtils.getScreenDensity().toInt()
        params.gravity = Gravity.TOP or Gravity.RIGHT
        params.width = ScreenUtils.getScreenWidth() / 2
        params.height = ViewGroup.LayoutParams.WRAP_CONTENT
        window.attributes = params
複製代碼

可是咱們用Anko是這樣的:

val countries = listOf("Russia", "USA", "Japan", "Australia")  //傳list
selector("Where are you from?", countries, { dialogInterface, i ->
    toast("So you're living in ${countries[i]}, right?")
})
複製代碼

看起來只是簡化了dialog的建立過程。

2.2.5 Progress dialogs

不顯示進度的 Loading Dialg

pressDialog("Please wait a minute.", "Downloading…")
indeterminateProgressDialog("Fetching the data…")
複製代碼

2.3 Logging

打印log輔助工具。

Android SDK 提供 android.util.Log 類來提供一些 logging 方法,,這些方法都很實用,可是咱們每次必須傳遞一個 Tag 參數,同時這個 Tag 信息必須是 String 類型的,這就略顯麻煩。不過如今咱們能夠經過 AnkoLogger 類擺脫這些惱人的問題:

class SomeActivity : Activity(), AnkoLogger {
    fun someMethod() {
        info("Info message")
        debug(42) // .toString() method will be called automatically
    }
}
複製代碼

默認的 Tag 名是當前的類名( 本例中的是SomeActivity),可是經過重寫 AnkoLogger 的 loggerTag 屬性咱們是能夠來更改的,並且每一個方法有兩個版本:plain and lazy (inlined)

1.Lazy:

info("String " + "concatenation")
info { "String " + "concatenation" }
複製代碼

2.plain:

class SomeActivity : Activity() {
    private val log = AnkoLogger(this.javaClass)
    private val logWithASpecificTag = AnkoLogger("my_tag")

    private fun someMethod() {
        log.warning("Big brother is watching you!")
    }
}
複製代碼

上面兩種方法分別是不一樣Tag的實現方式。

AnkoLogger中loggerTag 屬性具體對照以下:
在這裏插入圖片描述
2.4 Resources and dimensions

你能夠在你的項目中使用Anko Resources and dimensions來簡化你的代碼,例如Color、Dimen等,顏色透明度直接色值.opaque就能夠,尺寸的話直接使用dip(dipValue)、sp(spValue)就能夠。在這裏面還有一個就是applyRecursively()用來控制子View的操做,如:

verticalLayout {
        textView{
            text = "EditText01"
            backgroundColor = 0xff000.opaque
            textSize = 14f
        }
        textView {
            text = "EditText02"
            backgroundColor = 0x99.gray.opaque
            textSize = 23f
        }
    }.applyRecursively {//若是是ViewGroup的話可使用applyRecursively來爲每一個Child View進行設置
        view -> when(view){
            is TextView -> view.textColor = Color.RED
        }
    }
複製代碼

3.Anko Layouts

一般咱們使用xml文件寫咱們的佈局,可是他有一些缺點如不是類型安全,不是空安全,解析xml文件消耗更多的CPU和電量等等。而Anko Layout可使用DSL(Domain Specific Language)動態建立咱們的UI,而且它比咱們使用Java動態建立佈局方便不少主要是更簡潔,它和擁有xml建立佈局的層級關係,能讓咱們更容易閱讀。(官方說的優勢)

舉個栗子:

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}
複製代碼

上面的代碼是否是很簡單易懂,固然,默認的控件並不能知足咱們的需求,例如咱們會更改字體的顏色及大小,會設置寬度和高度,會設置margin,padding值,那麼該如何實行呢,固然也很簡單,由於它的邏輯和xml書寫佈局是一個套路。例如如下實現

val textView=textView("我是一個TextView"){
                textSize = sp(17).toFloat()
                textColor=0xff000.opaque
            }.lparams{
                margin=dip(10)
                height= dip(40)
                width= matchParent
            }
複製代碼

配合上前面Common庫是否是很簡單呢?

這裏咱們不須要setContentView。直接寫在onCreate方法中就行。

在上面建立UI過程當中,咱們直接把建立UI的代碼寫在onCreate方法中了,固然,還有一種寫法。咱們建立一個內部類實行AnkoComponent接口,並重寫createView方法,該方法返回一個View,也就是咱們建立的佈局。修改以下

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        MyActivityUI().setContentView(this)
    }
}

class MyActivityUI : AnkoComponent<MyActivity> {
    override fun createView(ui: AnkoContext<MyActivity>) = with(ui) {
        verticalLayout {
            val name = editText()
            button("Say Hello") {
                onClick { ctx.toast("Hello, ${name.text}!") }
            }
        }
    }
}
複製代碼

如今咱們編譯運行,發現效果和佈局文件寫的界面是同樣的。可是它的性能是有優點的,其實吧並無發覺性能優點。無論怎樣,這種DSL確實便於閱讀,也很容易上手,在上面的代碼中,你可能注意到了dip(10),它表示將10dp轉換爲像素的意思,是Anko的擴展函數,說的擴展函數,若是閱讀過Anko的源碼咱們發現裏面大量的使用擴展函數,這也是Kotlin語言的優點之一。

這裏就簡單介紹下Layout的使用和優勢。可是我想各位看官在實際開發中也不必定會用,由於不可視化用起來實在難以接受。不過這種見仁見智吧。

4.Anko SQLite: a query DSL and parser collection for Android SQLite;

Anko SQLite是一個查詢解析SQLite的領域專用語言

SQLite 存在的不足:

  1. 過多須要實現的模板代碼;
  2. 經過字符串實現 SQL 命令,容易出錯,且編譯時沒法檢查;
  3. 每次須要手動關閉數據庫;
  4. 線程和同步訪問的問題;

隨着你應用的數據庫愈來愈複雜,暴露出來的問題也會越多。因此也難怪不少人會選擇 ORM 或者 NoSQL,但這帶來的方便性是以增長應用大小和方法數爲代價的。

若是你打算使用 Kotlin 來開發 Android 應用,那麼如今經過 Anko SQLite 就能夠很方便的進行 SQLite 操做了。好比能夠告別麻煩的 Cursor 和 ContentValue、內置安全機制,保證數據庫在執行全部代碼後可以關閉。

經過繼承 ManagedSQLiteOpenHelper 類來實現數據庫幫助類,推薦作法就是按照官方的實現:

class DatabaseHelper(ctx: Context) : ManagedSQLiteOpenHelper(ctx, "LibraryDatabase", null, 1) {
  companion object {
    private var instance: DatabaseHelper? = null

    @Synchronized
    fun Instance(context: Context): DatabaseHelper {
      if (instance == null) {
        instance = DatabaseHelper(context.applicationContext)
      }
      return instance!!
    }
  }

  override fun onCreate(database: SQLiteDatabase) {
    createTable(Book.TABLE_NAME, true, Book.COLUMN_ID to INTEGER + PRIMARY_KEY, Book.COLUMN_TITLE to TEXT, Book.COLUMN_AUTHOR to TEXT)
  }

  override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
    dropTable(Book.TABLE_NAME, true)
  }
}
複製代碼

訪問數據庫的推薦作法是經過依賴注入,或者爲 Context 添加一個 extension:

val Context.database: DatabaseHelper
  get() = DatabaseHelper.Instance(applicationContext)
複製代碼

下面這是一個簡單的 model 類:

data class Book(val id: Int, val title: String, val author: String) {
  companion object {
    val Book.COLUMN_ID = "id"
    val TABLE_NAME = "books"
    val COLUMN_TITLE = "title"
    val COLUMN_AUTHOR = "author"
  }
}
複製代碼

當數據庫準備好後,就能夠經過 use 方法來進行操做了。好比:

database.use {
    insert(Book.TABLE_NAME, Book.COLUMN_ID to 1, Book.COLUMN_TITLE to "2666", Book.COLUMN_AUTHOR to "Roberto Bolano")
}
複製代碼

最後,讓咱們來比較一下常見庫的大小:

在這裏插入圖片描述

要注意這裏 Anko SQLite 的依賴大小實際上是包含了 Kotlin Runtim (method count: 6298, DEX size: 1117 KB) 和 Anko Commons module (method count: 982, DEX size: 174 KB) 的。所以若是你是經過 Kotlin 來開發,Anko SQLite 增長的大小其實並無圖表顯示得那麼多。

所以,若是你在使用 Kotlin 作開發而且數據庫的複雜度不高,首推 Anko SQLite。但若是數據庫結構很是複雜,DAO 和 SQL 查詢可能會變得很痛苦,這時候 ORM 和 NoSQL 就是首選方案了。

5.Anko Coroutines: utilities based on the kotlinx.coroutines library.

Kotlin協程 協程本質上是一個輕量級的線程,支持咱們用同步寫法寫異步請求,而不用Callback。

doAsync(UI) {
    val data: Deferred<Data> = bg {
		// Runs in background
		getData()
    }

    // This code is executed on the UI thread
    showData(data.await())
}
複製代碼

咱們能夠用bg()在新的線程去作耗時操做,等返回結果再在UI線程進行操做。

具體協程教程咱們能夠看一下官方文檔

Kotlin協程

6.總結

Anko是Kotlin官方開發的一個讓開發Android應用更快速更簡單的Kotlin庫,而且能讓咱們書寫的代碼更簡單清楚更容易閱讀。 主要包含了如下幾個部分。

  1. Anko Commons: a lightweight library full of helpers for intents, dialogs, logging and so on;
  2. Anko Layouts: a fast and type-safe way to write dynamic Android layouts;
  3. Anko SQLite: a query DSL and parser collection for Android SQLite;
  4. Anko Coroutines: utilities based on the kotlinx.coroutines library.

Anko庫用起來很是的簡單方便,裏面設計到DSL和擴展函數。

關於DSL能夠看下這篇文章

Kotlin 之美—DSL篇

關於擴展函數能夠看下這篇文章

Kotlin 擴展函數詳解與應用

相關文章
相關標籤/搜索