初次嘗試用Kotlin實現Android項目

 

   起這個文內標題的緣由很簡單,就是對Kotlin抱有但願——能使Android的開發更簡潔、高效及安全。知道Kotlin是從簡書的一篇短文,愈來愈以爲將本身學習、實踐的過程和想法總結成文字分享出來,無論文筆好壞,內容多少,若能拋磚引玉就足以。因此,感謝寫了那麼多精彩文章的大神,而我纔剛從山腳啓程。html

  項目源碼放在Github上,感興趣的朋友能夠下載,歡迎送星和討論。Demo運行的動態效果圖以下:android

 

1. Kotlin在Android Studio中的環境配置git

  按照下面兩篇文章的介紹操做,就能完成Kotlin在Android Studio中的環境配置(Eclipse就不推薦了),並能學習到基礎語法和使用案例。若是有問題能夠百度、谷歌或參考分享的項目源碼中的Project及App的build.gradle設置,也能夠留言你們一塊兒討論。github

  http://kotlinlang.org/docs/tutorials/kotlin-android.html
數據庫

  http://kotlinlang.org/docs/tutorials/android-plugin.html
數組

  其實和引入普通插件相似,說簡單點就是作兩件事情:安全

  a 安裝Kotlin插件;ide

  b Porject和App的build.gradle文件中添加引用;函數

  若是配置沒問題了,在Studio工具欄的Code欄最下方會出現可將Java代碼轉爲Kotlin代碼的選擇項:工具

  若是自己就是kt格式,那該選項就是灰色不可點擊的。

 

2. Kotlin學習與編碼總結

   開發環境OK以後,做爲剛接觸Kotlin的初學者,有兩種選擇:

  a 直接新建Android項目與Kotlin文件,在學習的同時從無到有得敲Kotlin代碼;

  b 打開以前的Android項目,經過上述的轉化工具先將有一個和若干Java文件轉爲Kotlin代碼,經過閱讀轉化後的代碼能夠快速熟悉Android項目的Kotlin的代碼;

  推薦從第二種方法開始,比較簡單,並且通常在將Java代碼轉過來以後會有一些小錯誤或者警告,在修改的過程當中進步也是蠻大的。註明一下:Kotlin不僅是能在Android項目中替代Java,在其官網有詳細的介紹。

  下面着重講述一下由於Kotlin使得代碼變得簡潔、安全以及巧妙的幾個點,這門新語言日漸成熟,不可能將其特色經過一兩篇文章就能覆蓋到。隨着學習的深刻,以後會再進行補充。

2.1 text & setText()

1 text1.text = (Editable e)
1 text1.setText(CharSequence text)

  先來個簡單的,text1是某佈局中TextView組件的id。就這樣一句代碼,就能夠完成文本的設置了,沒有TextView類對象聲明,不用調用findViewById()查找,是否是簡潔好多。雖然說這中間有些步驟仍是須要Kotlin去默默處理,可是做爲開發者,效率明顯提高了。通常經常使用的是後面一種,由於CharSequence或者String的使用頻率較高。可是Kotlin的簡潔形式都趨向於obj.field,而不是setField()這樣的方法,只不過這裏將CharSequence轉爲Editable稍微麻煩了一點:

1 text1.text = Editable.Factory().newEditable(message)

2.2 @ & when () {}

1 login_image_sel.setOnClickListener(this@LoginFragment)
2 login_in.setOnClickListener(this@LoginFragment)
3 login_reg.setOnClickListener(this@LoginFragment)
4 login_out.setOnClickListener(this@LoginFragment)

  給四個id表明的組件設置點擊監聽,方法參數爲View.OnClickListener,若是類已經繼承了它並實現了其onClick()方法,那麼直接寫成表明本身的this便可。而@Name部分則是強調類名稱(不寫也不影響編譯、運行),可是寫上以後可讀性更強了,能夠說此@是寫成開發者(本身或將來看代碼的人)看的。

 1 override fun onClick(view: View) {
 2     val id = view.id
 3     when (id) {
 4         R.id.login_image_sel -> selectImageBtn()
 5         R.id.login_in -> loginInBtn()
 6         R.id.login_reg -> loginRegBtn()
 7         R.id.login_out -> loginOutBtn()
 8         else -> { }
 9     }
10 }

  第一行須要先解釋,Java代碼是這樣的:

1 @Override
2 public void onClick(View view) {}

  有幾個地方不一樣:

  a @Override->override;

  b default->public,Kotlin默認的訪問限制是public,因此能夠省略;

  c void->: Unit,Kotlin無返回值能夠省略,也能夠寫成: Unit,固然看我的習慣了;

1 override fun onClick(view: View): Unit {

  d View view->view: View,形參聲明形式,具體的後面會再提到;

  Kotlin用when解放了switch,仔細琢磨一下能夠發現,無論是代碼形式和行數都簡潔了很多。告別了原先Java的case、「:」、break及default,我認爲最直接的好處是進入when以後,只會執行匹配項對應的"->"後面那一個分支,不用每次都要當心翼翼地想在哪加break。

2.3 var & val

1 val id = view.id

  接着上面的話題,來看一下變量的定義。看到上面這句代碼,熟悉腳本語言的朋友會有親切感,因此有時候以爲Kotlin是在慢慢地將各門語言的優勢結合起來。

  val和var對應,前者定義不可能變量,後者定義可改變量。這時候將Java的final拿出來最合適了,Kotlin中限定不可變的重擔是由val來完成,它們限定的變量必須在聲明時就賦值(類直接屬性除外,具體的後面會再提到)。

  那麼上面說到方法形參時(view: View),view後面有類型View,其實在聲明變量時也是如此,來看幾個例子:

1 var int1: Int = 1
2 var int2 = 2
3 var str3: String? = null
4 val str4: String? = null

  聲明瞭四個變量:兩個可變Int型,一個可變String型,一個不可變String型。既然不可變,那麼在後面再次賦值時就會報錯了:

1 int1 = 2
2 int2 = 3
3 str3 = "Hello"
4 str4 = "Kotlin"  //會標紅線,鼠標移入顯示"Val cannot be reassigned"

  實踐過就會發現,Kotlin中不能再像Java那樣聲明變量了,好比:

1 var int3
2 var int4: Int

  這兩種都是不行的,會提示"Property must be initialized or  be abstract"。

  再來看是類型後的那個問號(String? = null),它表示聲明的變量是否容許爲null。這要和另外一種狀況區分開:聲明變量的時候還不肯定其值是什麼,解決方式能夠是先賦一個不影響程序的值。好比:

1 var str3: String = "will be reassigned later"

  ": String"類型限定部分能夠不加,編譯器會自動推斷,這樣處理就沒有「?」。

  那麼有人疑問加「?」和不加的根本區別在哪?就在於程序運行過程當中對變量的賦值,若是給沒有加「?」的變量賦值了null,程序就會異常。通常用在函數的形參中,好比定義的方法形參以下:

1 fun testNotNull(str: String) {}

  調用時傳給形參str的值是不能爲null的,這一特性很是有用。由於在大部分應用場景下均可以肯定須要的參數是否能夠null,好比讀取圖像的路徑不能爲空,經過索引訪問元素時列表不能爲空等等。這不是說能夠完美地解決由於null引發的異常,而是能夠將異常的點提早,或者說變量容易發現與消除。至於在不一樣場景怎麼用,還得深刻研究,並非所有限定爲NonNull就是最合適的。固然,非空限制在Java代碼中也能夠經過註解@NonNull來實現。

  「?」還有一個頗有用的地方是方法返回值:

1 fun getStringLength(obj: Any): Int? {
2     if (obj is String)
3         return obj.length // no cast to String is needed
4     return null
5 }

  在Java中聲明爲int返回值類型後,是不容許返回null值的,可能會在沒有想要的結果時返回一個標記數值。而在Kotlin中只要檢查返回值是否爲null,若是不是則返回值就是但願獲得的結果。上面的代碼還能夠簡寫爲:

1 fun getStringLength(obj: Any): Int? = if (obj is String) obj.length else null

  這裏有一個新的知識,is的做用是判斷obj是不是String類型實例應用,若是不是則直接返回null,Java是instanceof。

2.4 Any

  Any有點像Java中的Object,對象的祖先。直接上例子:

1 fun showLog(message: Any?) {
2     Log.i(LOG_TAG, message?.toString())
3 }

  這是在Utils文件中自定義的一個實現log的方法,形參message的類型時Any?,正好鞏固一下上一條的概念。對於傳入的實參,能夠是null,也能夠是任意類型的變量值;重點在於message後面的那個「?」,它會判斷message是否爲null,若是是則直接返回字串「null」,若是不是纔去調用toString()方法。注意這裏假設傳入的實參對象繼承或重寫了toString(),不然可能會出錯。

2.5 Custom View

  這裏說的並非熟悉的自定義一個圓形View,而後在xml或者Java中進行使用,而是直接在代碼中生成佈局與組件,這又是Kotlin的一個優勢。來看定製一個Dialog的代碼:

 1 val dialog = Dialog(mContext, R.style.DialogNoTitle)
 2 dialog.setContentView(mContext.linearLayout {
 3     imageView {
 4         Utils.setImageToView(mContext, null, imageUri, this)
 5         onClick {
 6             dialog.dismiss()
 7         }
 8     }
 9 })
10 
11 dialog.show()

  代碼中的Style和Utils部分能夠在項目源碼中查看,這裏主要針對Kotlin定義佈局部分。動態添加線性佈局和一個圖像組件只須要聲明一個名稱便可,分別爲linearLayout和imageView。能夠理解爲包含的元素以{}爲界,imageView屬於linearLayout,而onClick {}和this則是屬於imageView。測試發現,顯示的Dialog默認就是居中的,想達到其餘效果進行相應的調整便可。

2.6 Map

1 `object`.map {
2     var bulletinT = ReceiveBulletin(it.teacherName,
3             it.updatedAt,
4             it.bulletinContent,
5             it.bulletinImage?.fileUrl)
6     //do something
7 }
  這裏的`object`能夠是列表數據,也能夠是數組等其餘集合類型。map的做用就是遍歷集合中的每個元素,對其在{}中進行處理,而每一個元素的臨時名稱爲「it」。這樣,是否是又能夠不用看到for或者Iterator了。

2.7 Class

  2.3中提到過val聲明的變量也能夠先不賦值,這種狀況會在Class的聲明時出現:

1 class BulletinAdapter(private val mContext: Context,
2                       private val mBulletins: ArrayList<ReceiveBulletin>)
3         : RecyclerView.Adapter<BulletinAdapter.ViewHolder>() {}

  自定義了一個和RecyclerView結合使用的Adapter類,類的繼承由Java的extends變成了冒號「:」,彷彿進入了C++的世界。

  類名後面居然跟了一個括號「()」,並且還多了那麼多奇怪的參數,Kotlin的解釋是這樣寫至關於快捷的構造函數。其實能夠理解爲primary constructor方法省略了名稱,若是方法前有註解等特殊修改,那麼名稱「constructor」是不能省略的。之因此說類後面跟着的方法爲primary,是由於在類中還能夠實現secondary constructors,之後用到時再深挖吧。而init是在類對象構造時就會調用一次,僅此一次,因此能夠做爲類實例時的標記,好比打印log:

1 init {
2     Utils.showLog("Create a BulletinAdapter object")
3 }

  val就不解釋了,傳入的實參賦給形參變量後,在本類中是不容許改變的。可是集合有點特殊,好比從新給mContext賦值不行,可是給mBulletins經過add()方法添加元素是能夠的,這裏涉及到對象指向的地址和包含的元素問題,先不展開。

  添加了private訪問限定符的目的和Java中相似,在類外不可見,即不容許在類外面對變量進行訪問與更改。

2.8 if ()  {} else () {}

  以前2.2中when分支->後面代碼都只有一句,若是有兩句呢?先看看if else的情形:

1 if (position == itemCount - 1)
2     itemView.bulletin_divider.visibility = View.GONE
3 else
4     itemView.bulletin_divider.visibility = View.VISIBLE

  當分支下有多個語句時,必須將屬於分支的全部代碼都包含在{}中,不然會出現下面的else匹配不到if的錯誤,這點和Java中的也是相同的。最後提一下Kotlin中不推薦在語句後寫分號「;」,寫上也沒錯,只是給變量名下面畫一條灰色的提醒而已。

 

3. 總結

3.1 項目介紹

  開頭給出了項目源碼下載地址和運行動態效果圖,如今來進行簡單的介紹。本身學習過程當中練手的不能叫作App,確切地應該叫Demo。

  Demo一共三個頁面:消息接收、消息發送及用戶信息。

  a 消息接收:打開程序時,會從雲數據庫中讀取消息,若是有則加載,沒有則顯示提示信息(如稍後下拉刷新等);一條信息包括髮送者頭像、名稱、發送時間、信息內容(文字或圖片至少有其一);若是有圖片內容,則點擊後放大;消息的接收沒有用戶登陸要求;

  b 發送消息:只有註冊並登陸的用戶才能進行消息的發送;發送的內容至少要有文字或圖片內容其中之一;

  c 用戶信息:先進行註冊,不能設置數據庫中已存在的用戶名,必定要選擇頭像,成功後通常會自動登陸;登錄後才能進行註銷操做;註銷後才能進行再次登陸操做;

這裏說的雲數據庫指的是項目中用到的免費的Bmob雲平臺,比較適合我的練習用,能夠本身建表及定義表中的信息。

3.2 Kotlin將來學習計劃

  文中提到的和項目中用到的知識點,都只是Kotlin語言的冰山一角。還有更有趣、奇妙的的地方值得去發現,相信之後能夠在項目中將之前習覺得常的、繁瑣的代碼進行更簡潔、高效的實現。

相關文章
相關標籤/搜索