關於做者html
郭孝星,程序員,吉他手,主要從事Android平臺基礎架構方面的工做,歡迎交流技術方面的問題,能夠去個人Github提issue或者發郵件至guoxiaoxingse@163.com與我交流。java
文章目錄android
注:文章中"舉例"字樣表明所舉的例子,"區別"字樣代碼Kotlin與Java不一樣的地方,git
更多文章請參見文章目錄。程序員
本篇文章是本系列文章的開篇文章,主要介紹Java中的編程概念(語句、函數、類等)是如何映射到Kotlin的代碼中的。本文的目的在於幫助你們快速理解Java裏的語法在Kotlin中如何實現,以及
它們之間有什麼區別。github
Kotlin是一種在Java虛擬機上運行的靜態類型編程語言。express
寫在前面的總結,從Java過分到Kotlin,有哪些被替換的地方。🤔apache
Android Stduio 3.0已經正式支持Kotlin,若是你是第一次接觸Kotlin,你能夠看一下下面3篇文章,跑一下Demo,體會一下Kotlin。編程
Kotlin常見的控制語句有:bash
Kotlin的控制語句和Java有所區別🤔,它們具有更強大的功能,在介紹控制語句以前,咱們要先理解兩條規則:
在Kotlin中,if是表達式,而在Java中if是語句。
關於Kotlin的表達式,有兩條規則須要咱們理解:
在Java中全部的控制語句都是表達式,而在Kotlin中,除了循環(for、do與do/while)是語句外,其餘大部分控制結構都是表達式,都有值。
而偏偏在Java中是表達式的賦值操做(a = 1)在Kotlin中倒是語句,這樣有助於避免比較操做(==)和賦值(=)操做之間的混淆。
有了上面兩條規則,咱們不難理解如下例子。
舉例
val a = 1
val b = 2
val ifResult = if (a > b) a else b
val whenResult = when (a > b) {
true -> a
else -> b
}
val number = try {
Integer.parseInt("1")
} catch (e: NumberFormatException) {
null
}
for (i: Int in 1..100){
Logger.d(i)
}
for((key, value) in map){
````//使用key,value
}
//變量 a 和 b 的值取自對集合中的元素上調用 component1() 和 component2() 的返回值。
for ((a, b) in collection) { …… }複製代碼
Kotlin提供了很是多相似於RxJava的操做符,爲平常的開發提供了極大的方便。更多操做符能夠參考操做符列表
函數還能夠用中綴表示法調用,當它們是成員函數或擴展函數;它們只有一個參數;它們用 infix 關鍵字標註。
/** * 用infix定義一箇中綴函數 */
infix fun Int.shl(x: Int) {
println("I am a infix method")
}
/** * 中綴調用 */
fun useInfixMethod() {
1 shl 2
}複製代碼
解構聲明是將一個對象解構成多個變量,一個解構聲明會同時建立多個變量。
要實現解構聲明,咱們須要添加componentN函數,componentN函數指定要返回的域,並使用operator標記
class Teacher(val name: String, val age: Int) : Person(name, age), IBehavior {
override fun talk() {
super<Person>.talk()
super<IBehavior>.talk()
}
operator fun component1(): Any {
return name
}
operator fun component2(): Any {
return age
}
}複製代碼
而後咱們就可使用解構聲明批量的建立變量,解構賦值是按照omponentN函數的順序來執行的。
val teacher = Teacher("LiLei", 20)
val (name, age) = teacher
Logger.d("name: " + name)
Logger.d("age: " + age)複製代碼
若是咱們在解構聲明中不須要某個變量,用下劃線代替便可。
val (_, age) = teacher複製代碼
函數的聲明以fun關鍵字開始,函數名稱緊跟其後,而後是形參列表,形參列表後面是返回值,若是沒有指定返回值,默認的返回值是Unit。
舉例
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}複製代碼
若是函數中只有一個表達式,能夠將這個表達式做爲完整的函數體,稱爲表達式函數體,例如:
fun max(a: Int, b: Int): Int = if (a > b) a else b複製代碼
Kotlin變量的聲明從關鍵字var與val開始,Kotlin會自動進行類型推導,所以你無需顯式的聲明類型。
舉例
val name = "Nick"
var age = 10複製代碼
默認狀況下,應該儘量的使用val關鍵字來聲明變量,僅在必要的時候使用var,使用不可變引用,不能夠對象以及無反作用的函數可讓你的代碼更加接近函數式編程風格。
注:這裏提一下Kotlin的package結構,和Java同樣Kotlin也有包的概念,可是Kotlin對源碼的文件組織更爲自由,多個類能夠在同一個文件中,文件的名字和目錄也能夠隨意選擇,可是咱們仍是
會按照Java的目錄佈局去組織源碼,這是一種良好的實踐,但在Kotlin中不少類都很是小,例如數據類,這種狀況下,咱們一般把它放在一個文件裏。
在Java中定義函數時,有些參數有默認值,這就致使會定義大量的重載函數(參考Thread的構造函數),而在Kotlin中能夠利用參數的默認值來避免這個問題。
/** * 函數能夠帶默認參數,@JvmOverloads註解能夠在編譯時生成重載函數 */
@JvmOverloads
fun maxWithDefault(a: Int = 1, b: Int = 2): Int {
return if (a > b) a else b
}複製代碼
注:可是Java中沒有參數默認值的概念,爲了方便Java調用Kotlin,能夠用@JvmOverloads去註解它,@JvmOverloads註解能夠在編譯時生成重載函數。
回想一下,咱們的項目中是否是有不少Utils類,它們一種靜態的方式被咱們調用。這些Utils類自己沒有實際意義,只是做爲函數的容器,而在Kotlin中咱們無需
這麼作,咱們能夠把這些函數和屬性直接定義在代碼文件的頂層,不用從屬任何類,而後用一種導包的方式使用它。
定義
/** * 頂層函數,能夠直接導包而後使用 */
val topProperty = "I am a top property"
/** * 頂層函數,能夠直接導包而後使用 */
fun topMethod(property: String) {
println("I am a top method")
}
class Method {
}複製代碼
調用
import com.guoxiaoxing.kotlin.demo._02_method.topMethod
import com.guoxiaoxing.kotlin.demo._02_method.topProperty
object MethodClient {
@JvmStatic
fun main(args: Array<String>) {
topMethod(topProperty)
}
}複製代碼
Kotlin的一大優點就在於它能夠平滑的與Java進行集成,例如咱們想要用Kotlin爲Java裏的類添加一個方法,這時咱們不要去修改Java的源碼,而是可使用擴展函數與屬性。
/** * 爲String類添加一個擴展屬性extensionProperty,這個String類能夠是Kotlin、Java甚至其餘任何JVM語言編寫的類 */
val String.extensionProperty
get() = "I am a extension property"
/** * 爲String類添加一個擴展函數extensionMethod(),這個String類能夠是Kotlin、Java甚至其餘任何JVM語言編寫的類 */
fun String.extensionMethod() {
println("I am a extension method")
}
/** * 使用擴展函數 */
fun useExtensionMethod() {
val a = "string"
a.extensionProperty
a.extensionMethod()
}複製代碼
好的代碼設計就是儘可能減小重複代碼,不少時候咱們會把重複的代碼提取成一個函數進行調用,Kotlin更進一步,它容許你在函數的內部定義函數進行調用。
/** * 爲了代碼的簡潔性,咱們還能夠定義局部函數 */
fun outerMethod() {
fun innerMethod() {
}
}複製代碼
Kotlin中類使用class關鍵聲明、接口使用Interface聲明,使用冒號(:)代替了extends與implements關鍵字,能夠實現多個接口,可是隻能繼承一個類。
Kotlin中也有和Java中類似的類與接口的概念,可是有所區別🤔
訪問修飾符
可見性
open class BaseClass {
open fun extendClass() {
}
}
interface BaseInterface {
val name: String
fun implementInterface()
}
class Clasz(override val name: String) : BaseClass(), BaseInterface {
override fun extendClass() {
println("I override the BaseClass")
}
override fun implementInterface() {
println("I implment the BaseInterface")
}
}複製代碼
構造方法
Kotlin裏的構造方法分爲主構造函數和從構造方法,主構造函數是類頭的一部分,它跟在類名後,類初始化的代碼能夠放在init代碼塊裏完成。Kotlin也支持參數默認值,因此咱們無需像Java那樣提供多個重載的構造方法來提供參數默認值。
class Clasz(override val name: String){
/**************************************** 構造方法與初始化 *********************************************/
init {
//TODO 初始化類,在類建立時被調用
}
/** * 從構造函數 * * 若是類有一個主構造函數,每一個次構造函數須要委託給主構造函數, 能夠直接委託或者經過別 * 的次構造函數間接委託。委託到同一個類的另外一個構造函數用 this 關鍵字便可 */
constructor(name: String, age: Int) : this(name) {
println("I am a secondary constructor")
}
}複製代碼
嵌套的類默認不是內部類,不持有外部類引用,也沒法使用外部類成員變量,若是想定義成內部類,須要用關鍵字inner聲明,內部類是持有外部類引用的,可使用
外部類成員變量。
class Clasz {
private var outerProperty = "I am a outer property"
/**************************************** 嵌套類與內部類 ***********************************************/
/** * 嵌套類,不持有外部類引用,也沒法使用外部類成員變量 */
class nestClass() {
fun nestMethod() {
}
}
/** * 內部類,持有外部類引用,可使用外部類成員變量 */
inner class innerClass() {
fun nestMethod() {
outerProperty = "I cam use outerProperty"
}
}
}複製代碼
在Java中咱們會用到協議只保存數據的類,咱們呀爲它們寫大量重複的方法,在Kotlin只須要用用data關鍵字標記。
data class Model(val name: String)複製代碼
就這麼簡單的一行代碼,你將獲得:
爲了保證數據類的一致性,數據類必須知足:
Kotlin沒有static的概念,可是提供了object關鍵字,它表明了在建立一個類的同時並提供一個對象。
object關鍵字一般用在:
object Single {
}複製代碼
/** * 匿名內部類 */
view.setOnClickListener(object : View.OnClickListener{
override fun onClick(v: View?) {
}
})複製代碼
另外還有一種companion object(伴生對象),伴生對象是一種聲明在類中的普通對象,它也能夠有本身的名字,實現一個接口或者有擴展函數和屬性。
Kotlin的伴生對象會被編譯成常見靜態字段,能夠經過ClassName.Companion來訪問它,若是伴生對象有名字,則用這個名字替換掉Companion。
class Singleton {
/** * 單例 */
companion object {
val instance by lazy { Singleton() }
}
}複製代碼
若是你尚未嘗試過Kotlin,Android Stduio 3.0已經正式支持Kotlin,若是你是第一次接觸Kotlin,你能夠看一下下面3篇文章,跑一下Demo,體會一下Kotlin。
利用kotlin-android-extensions,咱們能夠直接使用xml文件裏的文件id,和findViewById說再見。
注:目前只能在Activity、Fragment、Adapter上使用。
依賴配置
apply plugin: 'kotlin-android-extensions'複製代碼
導入屬性
// 使用來自主代碼集的 R.layout.activity_main
import kotlinx.android.synthetic.main.activity_main.*
// 若是是Adapter則在後面多加個View R.layout.adapter_layout
import kotlinx.android.synthetic.main.adapter_layout.view.*
class MyActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView.setText("Hello, world!")
// 而不是 findViewById(R.id.textView) as TextView
}
}複製代碼
更多細節:kotlinlang.org/docs/tutori…
Anke是一個Android開發的工具庫,它能夠經過Anko DSL代碼書寫代替XML來進行UI佈局。這是一個很是有效的特性,固然它也有許多有用的functions,能夠大大提高咱們的開發效率。
例如:
以上就是本篇文章上半部分的所有內容,下半部分咱們會來深刻探討泛型、註解、反射、Kotlin類型系統、Lambda與高階函數以及DSL構建等方面的內容。
--------------------------------------我是Kotlin項目的分割線😆------------------------------------------
Android平臺上圖片/視頻選擇,編輯和壓縮的一站式解決方案。
圖片/視頻的選擇,編輯和壓縮是業務中的常見需求,Phoenix完整的實現了這些功能,並提供了優雅的調用方式。Phoenix的核心功能基於Kotlin實現,外層接口基於Java實現,方便Kotlin與Java雙方的調用。
特色
功能
主題
在項目根目錄build.gradle文件裏添加
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}複製代碼
添加依賴
//圖片/視頻選擇、拍照、圖片/視頻預覽
compile 'com.github.guoxiaoxing.phoenix:phoenix-ui:0.0.11'
//選填 - 圖片壓縮,開啓功能:Phoenix.with().enableCompress(true),獲取結果:MediaEntity.getCompressPath()
compile 'com.github.guoxiaoxing.phoenix:phoenix-compress-picture:0.0.11'
//選填 - 視頻壓縮,開啓功能:Phoenix.with().enableCompress(true),獲取結果:MediaEntity.getCompressPath()
compile 'com.github.guoxiaoxing.phoenix:phoenix-compress-video:0.0.11'複製代碼
Phoenix.with()
.theme(PhoenixOption.THEME_DEFAULT)// 主題
.fileType(MimeType.ofAll())//顯示的文件類型圖片、視頻、圖片和視頻
.maxPickNumber(10)// 最大選擇數量
.minPickNumber(0)// 最小選擇數量
.spanCount(4)// 每行顯示個數
.pickMode(PhoenixConstant.MULTIPLE)// 多選/單選
.enablePreview(true)// 是否開啓預覽
.enableCamera(true)// 是否開啓拍照
.enableAnimation(true)// 選擇界面圖片點擊效果
.enableCompress(true)// 是否開啓壓縮
.thumbnailHeight(160)// 選擇界面圖片高度
.thumbnailWidth(160)// 選擇界面圖片寬度
.enableClickSound(true)//ƒ 是否開啓點擊聲音
.pickedMediaList(pickList)// 已選圖片數據
.videoSecond(0)//顯示多少秒之內的視頻
.onPickerListener(new OnPickerListener() {
@Override
public void onPickSuccess(List<MediaEntity> pickList) {
adapter.setList(pickList);
adapter.notifyDataSetChanged();
}
@Override
public void onPickFailed(String errorMessage) {
}
}).start(MainActivity.this, PhoenixOption.TYPE_PICK_MEDIA);複製代碼
最後的start()方法用來完成啓動某項功能,根據type不一樣啓動不一樣的功能,具體含義以下:
//功能 - 選擇圖片/視頻/音頻
public static final int TYPE_PICK_MEDIA = 0x000001;
//功能 - 拍照
public static final int TYPE_TAKE_PICTURE = 0x000002;
//功能 - 預覽
public static final int TYPE_BROWSER_PICTURE = 0x000003;複製代碼
歡迎加入改進本項目
Copyright 2017 Guoxiaoxing
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.複製代碼