kotlin是啥?這裏就不用多說了,想必看這篇文章的童鞋確定是有所瞭解的。html
那麼這篇文章你能夠收穫什麼?java
答:本文主要經過本人如何從java轉戰到kotlin並應用在實際項目中的我的經歷,給你們提供一些學習思路、學習方法以及一些學習資料和我的總結。android
前提:你的項目(包含我的項目)即將開始用到kotlin(沒有項目做爲依託你會缺乏十足的動力,並且缺乏應用場景乘熱打鐵那也是白學) 建議:建議沒有切換kotlin的小夥伴快來轉戰kotlin吧!最近一段時間搞了kotlin以後發現寫起來確實比java爽多了,語法很是精簡,並且據統計現已有30%安卓項目使用了kotlin,因此小夥伴們行動起來吧,這一定是大勢所趨,可千萬別被淘汰了啊git
俗話說萬事開頭難,不過咱們先把Kotlin語法學習一遍,你就會發現so easy,並且語言思想都是相通的github
固然是去官網學習嘍:kotlinlang.org/docs/refere…數據庫
以下圖:編程
不過英文吃力的小夥伴能夠去菜鳥教程網站學習json
地址:www.runoob.com/kotlin/kotl…設計模式
以下圖:瀏覽器
內容與官網一致。
不過不能光看,必定要寫,就算照着抄也要多寫,儘可能在學習時候多和java語法作對比,會印象深入。 以下圖,本人的練習代碼:
你們能夠參考下面的連接進行學習:
from-java-to-kotlin : github.com/MindorksOpe…
from-java-to-kotlin中給出了咱們經常使用的語法對比
如圖:
經過上面的學習咱們此刻已經熟悉了kotlin的基本語法,能夠來嘗試寫一個萬年曆的Demo。
咱們新建一個工程,點擊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"
複製代碼
該項目使用MVP模式,裏面用到了Retrofit2+RxJava2,而後使用了聚合的萬年曆接口,Demo很是簡單便於初學者快速掌握。
Demo使用展現:
工程目錄結構如圖:
看下佈局文件很是簡單,咱們能夠在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中生成。
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())
})
複製代碼
在寫項目的時候,通常會將常量統一寫到一個類裏面,而後設置靜態變量,因爲在Kotlin中不存在靜態變量,全部就有對象聲明的存在,對象聲明比較經常使用的地方就是在這裏,對象聲明用Objcet關鍵字表示。
object Constants {
val REQUEST_BASE_URL = "http://v.juhe.cn/"
val KEY = "1be865c0e67e3"
}
複製代碼
使用的時候直接類名加.加變量名,如Constants.REQUEST_BASE_URL
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
)
複製代碼
就是如此方便
kotlin的MVP和java原理如出一轍我先定義了IBaseModel
和IBaseView
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設計模式以及一些進階知識~
本文只列出幾個經常使用的設計模式
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
複製代碼
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
複製代碼
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
複製代碼
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
複製代碼
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
複製代碼
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 Dialog@5f184fc6
複製代碼
我的認爲仍是須要找一本書籍好好地閱讀一遍,一下提供了相關書籍能夠選擇適合本身的。
《Kotlin for Android Developers》
Kotlin是編寫Android應用程序的新官方語言,多虧了這本書,你很快就能寫出代碼。直奔主題,實用和完整的例子,它將在開發Android應用程序的同時展現你的語言。學習Kotlin並開始使用這個強大而現代的語言再次享受Android開發。
《Kotlin開發快速入門與實戰》
學習本書以前不須要具有任何的計算機專業背景,任何有志於APP開發的讀者都能利用本書從頭學起。
資深軟件開發工程師根據Kotlin最新版本撰寫,系統講解Kotlin開發技巧和項目實戰。全書共分爲7章,內容層次清晰,難度按部就班。但願經過閱讀本書,可以讓你成爲一個全棧工程師。
《瘋狂Kotlin講義》
本書尤爲適合從Java轉Kotlin的讀者,對於沒有Java功底的讀者,可忽略「對比」部分,直接學習本書也可掌握Kotlin編程。
本書對Kotlin的解讀十分系統、全面,超過Kotlin官方文檔自己覆蓋的內容。本書不少地方都會結合Java字節碼進行深刻解讀,好比對Kotlin擴展的解讀,對Kotlin主、次構造器的解讀,這種解讀目的不止於教會讀者簡單地掌握Kotlin的用法,而是力求讓讀者深刻理解Kotlin,且更好地理解Java。
《Kotlin實戰》
本書主要面向有必定Java 經驗的開發者。
本書將從語言的基本特性開始,逐漸覆蓋其更多的高級特性,尤爲注重講解如何將 Koltin 集成到已有 Java 工程實踐及其背後的原理。本書分爲兩個部分。第一部分講解如何開始使用 Kotlin 現有的庫和API,包括基本語法、擴展函數和擴展屬性、數據類和伴生對象、lambda 表達式,以及數據類型系統(着重講解了可空性和集合的概念)。第二部分教你如何使用 Kotlin 構建本身的 API,以及一些深層次特性——約定和委託屬性、高階函數、泛型、註解和反射,以及領域特定語言的構建。
本書適合廣大移動開發者及入門學習者,尤爲是緊跟主流趨勢的前沿探索者。
《揭祕Kotlin編程原理》
本書深刻介紹Kotlin面向對象設計的語法特性及其背後的實現方式。
在本書中,讀者不只能清晰地瞭解Kotlin的語法、高級特性,還能真正地掌握Kotlin背後的實現機制和設計哲學,造成對Kotlin語言既直觀、又深入的認識——在此基礎上,讀者能準確、快速地上手實踐,大大提高本身的移動開發能力。
Kotlin的這些特性和實現機制,能夠幫助開發者掃清開發道路上的一些障礙,讓開發變得更加簡單!本書是一本值得擁有,能切實幫助讀者加薪提職的好書!
學習一門語言最快的方式就是看其如何在實際項目中運用,有了上面的基礎和進階,下面咱們看一些開源項目:
介紹:這個項目實際上是Kotlin-for-Android-Developers這本書的配套代碼,若是你是kotlin的初學者,那麼這絕對是你學習kotlin的不二之選。項目經過一個天氣的例子很好的展現了kotlin帶來的強大功能,好比網絡數據的請求,數據的緩存設計,數據庫的操做,各類擴展函數的妙用等等。
介紹:Kotlin版本的音樂播放器,數據來源於LastFm。
介紹:gank.io kotlin實現的乾貨集中營Android客戶端,風格採用了Material Design。
介紹:一個用Kotlin寫的簡單漫畫APP。
介紹:Kotlin版本的Eyepetizer客戶端
介紹:Kotlin版本的吐槽客戶端
Kotlin 官方網站是學習 Kotlin 好去處。在參考部分,你能夠找到該語言的全部概念和功能的深刻解析文檔。在教程部分有關於設置工做環境並使用編譯器的實用分步指南。
這裏還有個 Kotlin 編譯器,是一個瀏覽器 APP,你能夠在上面嘗試使用這門語言。它能加載許多示例,包括 Koans 課程 — 這是目前熟悉 Kotlin 語法的最好方式。
Kotlin 的官方博客由 JetBrains 的一位做者負責。你能夠在這裏找到全部與 Kotlin 相關的新聞、更新、教程、使用技巧等的內容。
developer.android.com/kotlin/get-…
一篇很牛叉的文章,向咱們展現瞭如何使用 Kotlin 編寫和運行 Android 應用程序的測試
實用的快速提醒列表工具包含了一些簡短的代碼塊,藉由這個來幫助你快速找到通用 Java 操做符、功能以及聲明的 Kotlin 替代方案。
blog.jetbrains.com/kotlin/2016…
用於 IntelliJ IDEa 的插件,可以讓你在本地離線環境下使用 Koans 課程。
Kotlin 於 2012 年開源,你能夠對該語言進行貢獻。
Android 項目模板,使其很是容易設置穩定的 Kotlin 工做區,並快速引導你開發應用程序。
這是一個比較完整的 Kotlin 資源列表,包括各類實用連接、書籍、庫、框架和視頻等。該列表的組織結構很是好,kotlin.link 也提供了一個風格化的版本。
DariuszBaciński 建立了一個 GitHub repo,其中有在 Kotlin 中實現的常見設計模式,也有用其餘語言編寫的相似項目,包括 Java,Swift,Java 和 PHP,若是你是其中一項語言的使用者,能夠用它們做爲參考點。
來自 Google I / O 2017 的演講,大會首次向人們介紹 Kotlin,並提出了改進工做流程的想法。它涵蓋了許多基礎知識,並展現了一些很酷的 Kotlin 技巧。
Google I / O 2017 大會關於 Kotlin 的第二個演講。這個演講涵蓋了更多高級話題,如設計模式,最佳實踐和其餘常見規則。 演講也揭示了在生產中使用 Kotlin 的意義,以及在工做中採用新興語言將面臨的挑戰。
這是一個免費的 Kotlin 課程,適合初學者,前面介紹了從變量到條件循環和函數的全部基礎知識,後面會深刻到更高級的主題,如 Kotlin 中的面向對象以及像 lambda 表達式的功能編程。
這個講座從 2016 年開始,它介紹了現實世界中的編程語言功能,你將瞭解到 Kotlin 是如何適應 Android 工做流程中存在的工具。
一個 8 分鐘的濃縮教程,讓你快速瞭解 Kotlin 的主要功能,如變量聲明、Lambdas、擴展功能等等。
關於 Kotlin 的介紹,演講向咱們解釋了新語言是如何改進 Android 生態系統的,並展現了許多炫酷的方式,咱們可使用智能的 Kotlin 語法來得到優點。