1. 程式人生 > >Android快速轉戰Kotlin教程

Android快速轉戰Kotlin教程

前言

kotlin是啥?這裡就不用多說了,想必看這篇文章的童鞋肯定是有所瞭解的。

那麼這篇文章你可以收穫什麼?

答:本文主要通過本人如何從java轉戰到kotlin並應用在實際專案中的個人經歷,給大家提供一些學習思路、學習方法以及一些學習資料和個人總結。

前提:你的專案(包含個人專案)即將開始用到kotlin(沒有專案作為依託你會缺少十足的動力,而且缺少應用場景乘熱打鐵那也是白學)
建議:建議沒有切換kotlin的小夥伴快來轉戰kotlin吧!最近一段時間搞了kotlin之後發現寫起來確實比java爽多了,語法非常精簡,而且據統計現已有30%安卓專案使用了kotlin,所以小夥伴們行動起來吧,這必定是大勢所趨,可千萬別被淘汰了啊

入門

俗話說萬事開頭難,不過我們先把Kotlin語法學習一遍,你就會發現so easy,而且語言思想都是相通的

第一步:學習語法

如下圖:

不過英文吃力的小夥伴可以去菜鳥教程網站學習

如下圖:

內容與官網一致。

不過不能光看,一定要寫,就算照著抄也要多寫,儘量在學習時候多和java語法做對比,會印象深刻。
如下圖,本人的練習程式碼:

第二步:對比學習

大家可以參考下面的連結進行學習:

from-java-to-kotlin中給出了我們常用的語法對比

如圖:

第三步:Demo練習

通過上面的學習我們此刻已經熟悉了kotlin的基本語法,可以來嘗試寫一個萬年曆的Demo。

1、新建工程

我們新建一個工程,點選Include kotlin support
如圖:

我們看一下Include kotlin support都幫我們做了什麼事情

首先module中gradle檔案

如圖:

比我們之前的工程多了下面兩個引用和一個依賴:

// 使用Kotlin外掛
apply plugin: 'kotlin-android'
// 使用Kotlin Android擴充套件外掛
apply plugin: 'kotlin-android-extensions'

dependencies {
    //...
    //新增Kotlin 標準庫
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
//... }

知識點: kotlin-android-extensions相當於DataBinding,同樣的目的為了偷懶不用寫findViewByIdAndroid 開發必備。

我們再看一下project中的gradle檔案
如圖:

比我們之前的工程多了Kotlin編譯外掛:

// 添加了Kotlin編譯外掛
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

2、Demo說明

該專案使用MVP模式,裡面用到了Retrofit2+RxJava2,然後使用了聚合的萬年曆介面,Demo非常簡單便於初學者快速掌握。

Demo使用展示:

工程目錄結構如圖:

3、Activity

看下佈局檔案非常簡單,我們可以在activity裡面直接將控制元件的id當成變數來使用

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ....">

    <DatePicker
        android:id="@+id/dataPicker"
        .... />

    <Button
        android:id="@+id/selectButton"
        .... />

    <TextView
        android:id="@+id/titleTextView"
        .... />

    <TextView
        android:id="@+id/contentTextView"
       ....
       />

</android.support.constraint.ConstraintLayout>
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    selectButton.setOnClickListener {
        titleTextView.visibility = View.GONE
        selectButton.visibility = View.GONE
        contentTextView.visibility = View.GONE
        dataPicker.visibility = View.VISIBLE
    }
    ....
    ....
}

注意:直接使用id作為變數的時候,要在Module的gradle裡面加入擴充套件,才能使用,不然會報錯

apply plugin: 'kotlin-android-extensions'

這個上面已經說過,我們建立工程的時候如果選中Include kotlin support怎會自動在gradle中生成。

4、Retrofit+RxJava

Retrofit結合RxJava能快捷的使用網路請求。

建立Service介面,Kotlin的型別是寫在後面

interface RetrofitService {

    /**
     *  獲取當天詳細資訊
     *  @param date 日期
     */
    @GET("calendar/day")
    fun calenderDay(
            @Query("date") date: String,
            @Query("key") key: String
    ): Observable<CalentarDayBean>

    /**
     *  獲取近期假期
     *  @param date 日期
     */
    @GET("calendar/month")
    fun calenderMonth(
            @Query("date") date: String
    ): Observable<CalentarMonthBean>

    /**
     *  獲取當年假期列表
     *  @param date 日期
     */
    @GET("calendar/year")
    fun calenderYear(
            @Query("date") date: String
    ): Observable<CalentarYearBean>
}

建立Retrofit,Kotlin的class並不支援static變數,所以需要使用companion object來宣告static變數,其實這個變數也不是真正的static變數,而是一個伴生物件

伴生物件可以實現靜態呼叫,通過類名.屬性名或者類名.方法名進行呼叫

class RetrofitUtil {
    companion object {
        /**
         * 建立Retrofit
         */
        fun create(url: String): Retrofit {
            //日誌顯示級別
            val level: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.BODY
            //新建log攔截器
            val loggingInterceptor: HttpLoggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
                message -> Logger.e("OkHttp: " + message)
            })
            loggingInterceptor.level = level
            // okHttpClientBuilder
            val okHttpClientBuilder = OkHttpClient().newBuilder()

            okHttpClientBuilder.connectTimeout(60, TimeUnit.SECONDS)
            okHttpClientBuilder.readTimeout(10, TimeUnit.SECONDS)
            //OkHttp進行新增攔截器loggingInterceptor
            //okHttpClientBuilder.addInterceptor(loggingInterceptor)

            return Retrofit.Builder()
                    .baseUrl(url)
                    .client(okHttpClientBuilder.build())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build()
        }

        val retrofitService: RetrofitService = RetrofitUtil.getService(Constants.REQUEST_BASE_URL, RetrofitService::class.java)

        /**
         * 獲取ServiceApi
         */
        fun <T> getService(url: String, service: Class<T>): T {
            return create(url).create(service)
        }
    }
}

通過伴生物件,結合Retrofit結合RxJava 我們直接就可以呼叫介面了

RetrofitUtil
    .retrofitService
    .calenderDay(date,"933dc930886c8c0717607f9f8bae0b48")
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ result ->
        view?.showDayCalentarData(result)
        Logger.e(result.toString())
    }, { error ->
        view?.showError(error.message.toString())
        Logger.e(error.message.toString())
    })

5、使用物件宣告

在寫專案的時候,一般會將常量統一寫到一個類裡面,然後設定靜態變數,由於在Kotlin中不存在靜態變數,所有就有物件宣告的存在,物件宣告比較常用的地方就是在這裡,物件宣告用Objcet關鍵字表示。

object Constants {

    val REQUEST_BASE_URL = "http://v.juhe.cn/"

    val KEY = "1be865c0e67e3"
}

使用的時候直接類名加.加變數名,如Constants.REQUEST_BASE_URL

6、使用資料類

Kotlin有專門的資料類,就是用data修飾的類
首先我們先看一下json資料:

{
    "reason":"Success",
    "result":{
        "data":{
            "date":"2018-4-4",
            "weekday":"星期三",
            "animalsYear":"狗",
            "suit":"訂盟.納采.冠笄.拆卸.修造.動土.安床.入殮.除服.成服.移柩.安葬.破土.啟攢.造倉.",
            "avoid":"作灶.開光.嫁娶.開市.入宅.",
            "year-month":"2018-4",
            "lunar":"二月十九",
            "lunarYear":"戊戌年"
        }
    },
    "error_code":0
}

再來看一下我的資料類:

data class CalentarDayBean(
    val reason: String,
    val result: CalentarDayResult,
    val error_code: Int
)

data class CalentarDayResult(
        val data: CalentarDayData
)

data class CalentarDayData(
        val date: String,
        val weekday: String,
        val animalsYear: String,
        val suit: String,
        val avoid: String,
        val yearMonth: String,
        val holiday: String,
        val lunar: String,
        val lunarYear: String,
        val desc: String
)

就是如此方便

7、MVP

kotlin的MVP和java原理一模一樣我先定義了IBaseModelIBaseView

IBaseModel

interface IBaseModel<T> {

    fun onDestroy()

    fun attachView(view: T)
}

IBaseView

interface IBaseView {

    fun showLoading()


    fun hideLoading()

    fun showMessage(message: String)

    fun killMyself()
}

然後完成ICalentarContract,這個類似合同類的介面把P和V的所有方法全部寫在一起,看起來程式碼格外清楚

interface ICalentarContract {
    /**
     * 對於經常使用的關於UI的方法可以定義到IBaseView中,如顯示隱藏進度條,和顯示文字訊息
     */
    interface View : IBaseView {
        fun showDayCalentarData(calentarDayBean: CalentarDayBean)
        fun showError(errorMsg: String)
    }

    /**
     * Model層定義介面,外部只需關心Model返回的資料,無需關心內部細節,如是否使用快取
     */
    interface Model : IBaseModel<ICalentarContract.View> {
        fun getDayCalentarData(date: String)
    }
}

然後activity去實現ICalentarContract.View,presenter去實現ICalentarContract.Model

class CalentarDatePresenter : ICalentarContract.Model {
....
}
class MainActivity : AppCompatActivity(), ICalentarContract.View {
...
}

so easy~~~ 到這裡我們的Demo就完成了,可以盡情玩樂。

專案地址:待上傳。。。。。。。。。。。。。

好了,到這裡我們基本掌握了Kotlin在安卓中的應用,那麼接下來就需要去學習一下kotlin設計模式以及一些進階知識~

進階

一、Kotlin設計模式

本文只列出幾個常用的設計模式

1、觀察者模式( observer pattern )

Example

interface TextChangedListener {
    fun onTextChanged(newText: String)
}

class PrintingTextChangedListener : TextChangedListener {
    override fun onTextChanged(newText: String) = println("Text is changed to: $newText")
}

class TextView {

    var listener: TextChangedListener? = null

    var text: String by Delegates.observable("") { prop, old, new ->
        listener?.onTextChanged(new)
    }
}

Usage

val textView = TextView()
textView.listener = PrintingTextChangedListener()
textView.text = "Lorem ipsum"
textView.text = "dolor sit amet"

Output

Text is changed to: Lorem ipsum
Text is changed to: dolor sit amet

2、策略模式( strategy pattern )

Example

class Printer(val stringFormatterStrategy: (String) -> String) {
    fun printString(string: String) = println(stringFormatterStrategy.invoke(string))
}

val lowerCaseFormatter: (String) -> String = { it.toLowerCase() }

val upperCaseFormatter = { it: String -> it.toUpperCase() }

Usage

val lowerCasePrinter = Printer(lowerCaseFormatter)
lowerCasePrinter.printString("LOREM ipsum DOLOR sit amet")

val upperCasePrinter = Printer(upperCaseFormatter)
upperCasePrinter.printString("LOREM ipsum DOLOR sit amet")

val prefixPrinter = Printer({ "Prefix: " + it })
prefixPrinter.printString("LOREM ipsum DOLOR sit amet")

Output

lorem ipsum dolor sit amet
LOREM IPSUM DOLOR SIT AMET
Prefix: LOREM ipsum DOLOR sit amet

3、單例模式(singleton pattern)

Example

class Singletone private constructor() {
    init {
        println("Initializing with object: $this")
    }

    companion object {
        val getInstance =SingletonHolder.holder
    }

    private object SingletonHolder {
        val holder = Singletone()
    }

    fun print() = println("Printing with object: $this")
}

Usage

Singletone.getInstance.print()
Singletone.getInstance.print()

Output

Initializing with object: advance.Singletone@266474c2
Printing with object: advance.Singletone@266474c2
Printing with object: advance.Singletone@266474c2

4、工廠模式(Factory Method)

Example

interface Currency {
    val code: String
}

class Euro(override val code: String = "EUR") : Currency
class UnitedStatesDollar(override val code: String = "USD") : Currency

enum class Country {
    UnitedStates, Spain, UK, Greece
}

class CurrencyFactory {
    fun currencyForCountry(country: Country): Currency? {
        when (country) {
            Country.Spain, Country.Greece -> return Euro()
            Country.UnitedStates          -> return UnitedStatesDollar()
            else                          -> return null
        }
    }
}

Usage

val noCurrencyCode = "No Currency Code Available"

val greeceCode = CurrencyFactory().currencyForCountry(Country.Greece)?.code() ?: noCurrencyCode
println("Greece currency: $greeceCode")

val usCode = CurrencyFactory().currencyForCountry(Country.UnitedStates)?.code() ?: noCurrencyCode
println("US currency: $usCode")

val ukCode = CurrencyFactory().currencyForCountry(Country.UK)?.code() ?: noCurrencyCode
println("UK currency: $ukCode")

Output

Greece currency: EUR
US currency: USD
UK currency: No Currency Code Available

5、代理模式(Protection Proxy)

Example

interface File {
    fun read(name: String)
}

class NormalFile : File {
    override fun read(name: String) = println("Reading file: $name")
}

//Proxy:
class SecuredFile : File {
    val normalFile = NormalFile()
    var password: String = ""

    override fun read(name: String) {
        if (password == "secret") {
            println("Password is correct: $password")
            normalFile.read(name)
        } else {
            println("Incorrect password. Access denied!")
        }
    }
}

Usage

val securedFile = SecuredFile()
securedFile.read("readme.md")

securedFile.password = "secret"
securedFile.read("readme.md")

Output

Incorrect password. Access denied!
Password is correct: secret
Reading file: readme.md

6、建造者模式(builder pattern)

Example

// Let's assume that Dialog class is provided by external library.
// We have only access to Dialog public interface which cannot be changed.

class Dialog() {

    fun showTitle() = println("showing title")

    fun setTitle(text: String) = println("setting title text $text")

    fun setTitleColor(color: String) = println("setting title color $color")

    fun showMessage() = println("showing message")

    fun setMessage(text: String) = println("setting message $text")

    fun setMessageColor(color: String) = println("setting message color $color")

    fun showImage(bitmapBytes: ByteArray) = println("showing image with size ${bitmapBytes.size}")

    fun show() = println("showing dialog $this")
}

//Builder:
class DialogBuilder() {
    constructor(init: DialogBuilder.() -> Unit) : this() {
        init()
    }

    private var titleHolder: TextView? = null
    private var messageHolder: TextView? = null
    private var imageHolder: File? = null

    fun title(init: TextView.() -> Unit) {
        titleHolder = TextView().apply { init() }
    }

    fun message(init: TextView.() -> Unit) {
        messageHolder = TextView().apply { init() }
    }

    fun image(init: () -> File) {
        imageHolder = init()
    }

    fun build(): Dialog {
        val dialog = Dialog()

        titleHolder?.apply {
            dialog.setTitle(text)
            dialog.setTitleColor(color)
            dialog.showTitle()
        }

        messageHolder?.apply {
            dialog.setMessage(text)
            dialog.setMessageColor(color)
            dialog.showMessage()
        }

        imageHolder?.apply {
            dialog.showImage(readBytes())
        }

        return dialog
    }

    class TextView {
        var text: String = ""
        var color: String = "#00000"
    }
}

Usage

//Function that creates dialog builder and builds Dialog
fun dialog(init: DialogBuilder.() -> Unit): Dialog {
    return DialogBuilder(init).build()
}

val dialog: Dialog = dialog {
    title {
        text = "Dialog Title"
    }
    message {
        text = "Dialog Message"
        color = "#333333"
    }
    image {
        File.createTempFile("image", "jpg")
    }
}

dialog.show()

Output

setting title text Dialog Title
setting title color #00000
showing title
setting message Dialog Message
setting message color #333333
showing message
showing image with size 0
showing dialog [email protected]5f184fc6

2、相關書籍

個人認為還是需要找一本書籍好好地閱讀一遍,一下提供了相關書籍可以選擇適合自己的。

NO.1

《Kotlin for Android Developers》

Kotlin是編寫Android應用程式的新官方語言,多虧了這本書,你很快就能寫出程式碼。直奔主題,實用和完整的例子,它將在開發Android應用程式的同時展示你的語言。學習Kotlin並開始使用這個強大而現代的語言再次享受Android開發。

NO.2

《Kotlin開發快速入門與實戰》

學習本書之前不需要具備任何的計算機專業背景,任何有志於APP開發的讀者都能利用本書從頭學起。

資深軟體開發工程師根據Kotlin最新版本撰寫,系統講解Kotlin開發技巧和專案實戰。全書共分為7章,內容層次清晰,難度循序漸進。希望通過閱讀本書,能夠讓你成為一個全棧工程師。

NO.3

《瘋狂Kotlin講義》

本書尤其適合從Java轉Kotlin的讀者,對於沒有Java功底的讀者,可忽略“對比”部分,直接學習本書也可掌握Kotlin程式設計。

本書對Kotlin的解讀十分系統、全面,超過Kotlin官方文件本身覆蓋的內容。本書很多地方都會結合Java位元組碼進行深入解讀,比如對Kotlin擴充套件的解讀,對Kotlin主、次構造器的解讀,這種解讀目的不止於教會讀者簡單地掌握Kotlin的用法,而是力求讓讀者深入理解Kotlin,且更好地理解Java。

NO.4

《Kotlin實戰》

本書主要面向有一定Java 經驗的開發者。

本書將從語言的基本特性開始,逐漸覆蓋其更多的高階特性,尤其注重講解如何將 Koltin 整合到已有 Java 工程實踐及其背後的原理。本書分為兩個部分。第一部分講解如何開始使用 Kotlin 現有的庫和API,包括基本語法、擴充套件函式和擴充套件屬性、資料類和伴生物件、lambda 表示式,以及資料型別系統(著重講解了可空性和集合的概念)。第二部分教你如何使用 Kotlin 構建自己的 API,以及一些深層次特性——約定和委託屬性、高階函式、泛型、註解和反射,以及領域特定語言的構建。

本書適合廣大移動開發者及入門學習者,尤其是緊跟主流趨勢的前沿探索者。

NO.5

《揭祕Kotlin程式設計原理》

本書深入介紹Kotlin面向物件設計的語法特性及其背後的實現方式。

在本書中,讀者不僅能清晰地瞭解Kotlin的語法、高階特性,還能真正地掌握Kotlin背後的實現機制和設計哲學,形成對Kotlin語言既直觀、又深刻的認識——在此基礎上,讀者能準確、快速地上手實踐,大大提升自己的移動開發能力。

Kotlin的這些特性和實現機制,可以幫助開發者掃清開發道路上的一些障礙,讓開發變得更加簡單!本書是一本值得擁有,能切實幫助讀者加薪提職的好書!

專案

學習一門語言最快的方式就是看其如何在實際專案中運用,有了上面的基礎和進階,下面我們看一些開源專案:

1.Kotlin-for-Android-Developers(★1676)

介紹:這個專案其實是Kotlin-for-Android-Developers這本書的配套程式碼,如果你是kotlin的初學者,那麼這絕對是你學習kotlin的不二之選。專案通過一個天氣的例子很好的展示了kotlin帶來的強大功能,比如網路資料的請求,資料的快取設計,資料庫的操作,各種擴充套件函式的妙用等等。

2.Bandhook-Kotlin (★1494)

介紹:Kotlin版本的音樂播放器,資料來源於LastFm。

3.GankClient-Kotlin (★1216)

介紹:gank.io kotlin實現的乾貨集中營Android客戶端,風格採用了Material Design。

4.PoiShuhui-Kotlin(★897)

介紹:一個用Kotlin寫的簡單漫畫APP。

5.Eyepetizer-in-Kotlin(★1167)

介紹:Kotlin版本的Eyepetizer客戶端

6.Tucao(★792)

介紹:Kotlin版本的吐槽客戶端

資源

一、重要資源

Kotlin 官網

Kotlin 官方網站是學習 Kotlin 好去處。在參考部分,你可以找到該語言的所有概念和功能的深入解析文件。在教程部分有關於設定工作環境並使用編譯器的實用分步指南。

這裡還有個 Kotlin 編譯器,是一個瀏覽器 APP,你可以在上面嘗試使用這門語言。它能載入許多示例,包括 Koans 課程 — 這是目前熟悉 Kotlin 語法的最好方式。

Kotlin 官博

Kotlin 的官方部落格由 JetBrains 的一位作者負責。你可以在這裡找到所有與 Kotlin 相關的新聞、更新、教程、使用技巧等的內容。

在 Android 上開始使用 Kotlin

一篇很牛叉的文章,向我們展示瞭如何使用 Kotlin 編寫和執行 Android 應用程式的測試

從 Java 到 Kotlin

實用的快速提醒列表工具包含了一些簡短的程式碼塊,藉由這個來幫助你快速找到通用 Java 操作符、功能以及宣告的 Kotlin 替代方案。

Kotlin 教學外掛

用於 IntelliJ IDEa 的外掛,可讓你在本地離線環境下使用 Koans 課程。

Kotlin on GitHub

Kotlin 於 2012 年開源,你可以對該語言進行貢獻。

Kotlin Android 模板

Android 專案模板,使其非常容易設定穩定的 Kotlin 工作區,並快速引導你開發應用程式。

不可錯過的 Kotlin 資源列表

這是一個比較完整的 Kotlin 資源列表,包括各種實用連結、書籍、庫、框架和視訊等。該列表的組織結構非常好,kotlin.link 也提供了一個風格化的版本。

kotlin設計模式

DariuszBaciński 建立了一個 GitHub repo,其中有在 Kotlin 中實現的常見設計模式,也有用其他語言編寫的類似專案,包括 Java,Swift,Java 和 PHP,如果你是其中一項語言的使用者,可以用它們作為參考點。

二、視訊資源

Kotlin 介紹

來自 Google I / O 2017 的演講,大會首次向人們介紹 Kotlin,並提出了改進工作流程的想法。它涵蓋了許多基礎知識,並展示了一些很酷的 Kotlin 技巧。

明日勝於今,我用 Kotlin

Google I / O 2017 大會關於 Kotlin 的第二個演講。這個演講涵蓋了更多高階話題,如設計模式,最佳實踐和其他常見規則。 演講也揭示了在生產中使用 Kotlin 的意義,以及在工作中採用新興語言將面臨的挑戰。

Peter Sommerhoff 教你學 Kotlin

這是一個免費的 Kotlin 課程,適合初學者,前面介紹了從變數到條件迴圈和函式的所有基礎知識,後面會深入到更高階的主題,如 Kotlin 中的面向物件以及像 lambda 表示式的功能程式設計。

使用 Kotlin&Gradle 更好地開發 Android

這個講座從 2016 年開始,它介紹了現實世界中的程式語言功能,你將瞭解到 Kotlin 是如何適應 Android 工作流程中存在的工具。

使用 Kotlin&Gradle 更好地開發 Android

一個 8 分鐘的濃縮教程,讓你快速瞭解 Kotlin 的主要功能,如變數宣告、Lambdas、擴充套件功能等等。

Jake Wharton:用 Kotlin 進行 Android 開發

關於 Kotlin 的介紹,演講向我們解釋了新語言是如何改進 Android 生態系統的,並展示了許多炫酷的方式,我們可以使用智慧的 Kotlin 語法來獲得優勢。

掃碼關注公眾號“偉大程式猿的誕生“,更多幹貨等著你~
掃碼關注公眾號“偉大程式猿的誕生“,更多幹貨等著你~
掃碼關注公眾號“偉大程式猿的誕生“,更多幹貨等著你~

公眾號回覆“資料獲取”,獲取更多幹貨哦~
公眾號回覆“資料獲取”,獲取更多幹貨哦~
公眾號回覆“資料獲取”,獲取更多幹貨哦~