極簡Kotlin-For-Android(一)

TheShy_發表於2018-12-19

安裝 Kotlin 外掛

Android Studio 3.+ 已經有了 Kotlin 外掛,如果是更早的版本,點選 Android Studio | File | Settings | Plugins,搜尋 Kotlin ,安裝,重啟 Android Studio .

建立工程

點選 Android Studio | File | New project : 勾選Incloud Kotlin support.
就會看到下面的類:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
複製程式碼

定義類

1.只需使用class關鍵字.
2.它有一個唯一預設的構造器,大部分情況下只需使用這個預設構造器即可.
3.建構函式的函式體,寫在init塊{}中

class Person(name:String ,age : Int) {
    init {
    }
}
複製程式碼

類繼承

1.上帝類是Any(類似於java中的Object)
2.所有類預設是不可繼承的(final),我們只能繼承宣告open或abstract的類

open class Animal(name: String)
class Person(name:String ,age : Int) : Animal(name) 
複製程式碼

函式(java中的方法)

1.使用fun關鍵字
2.如果沒有指定返回值,預設返回Unit(java中的void),當然也可以指定返回任何型別

fun add(age1:Int ,age2:Int) : Int{
    return age1+age2
}
複製程式碼

Tips: 分號不是必須的,結尾不使用分號會節約很多時間,養成這個好習慣吧!

3.如果返回結果可以使用表示式表達出來,直接使用等號:

fun add2(age1: Int , age2: Int) : Int = age1+age2
複製程式碼

構造方法和函式引數
1.kotlin中引數是先寫名稱,後寫型別....(有點不適應) 2.可以給引數一個指定預設值,使其變得可選,例如下面toast函式第二個引數給了預設值,呼叫時候可以不傳第二個值(java中過載方法的替換?)

fun toast(msg : String , length : Int = Toast.LENGTH_LONG){
    Toast.makeText(this,msg,length).show();
}

toast("列印吐司鴨")
toast("列印吐司鴨",Toast.LENGTH_SHORT)
複製程式碼

Tips:
String模板內插*:

val name = "susan"
println("name : $name")
輸出結果: name : susan
複製程式碼

編寫你的第一個類

我們在MainActivity的佈局檔案中加入RecyclerView,然後設定好LayoutManager:

val recycler = findViewById(R.id.recycler) as RecyclerView
recycler.layoutManager = LinearLayoutManager(this)
複製程式碼

如上程式碼,LayoutManager會通過屬性設定,而不是通過set方法.
物件例項化也去掉了new關鍵字,建構函式仍然會被呼叫. 接著設定Adapter:

class ForecastListAdapter(val items : List<String>) : RecyclerView.Adapter<ForecastListAdapter.ViewHolder>(){
    //繫結資料
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.textView.text = items[position]
    }
    //返回list count
    override fun getItemCount(): Int {
        return items.size
    }
    //建立viewHolder
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(TextView(parent.context))
    }
    class ViewHolder(val textView : TextView) : RecyclerView.ViewHolder(textView)
}
複製程式碼

回到MainActivity,現在我們將少量資料放入recyclerview中:

    //定義天氣陣列陣列
    val weaList= listOf<String>(
            "北京 -0 -  微風",
            "北京 -10 - 微風",
            "北京 -13 - 微風",
            "北京 -20 - 微風",
            "北京 -5 -  微風"
            )
recycler.adapter = ForecastListAdapter(weaList)
複製程式碼

關於List的建立:
可以通過一個函式listOf建立一個常亮list,它接收任何型別的vararg(可變長度引數).還有很多其他函式:setOf,arrayListOf hashSetOf, etc...

執行你的專案吧:

極簡Kotlin-For-Android(一)
接下來,必須要學習一些基本型別,變數,屬性等才能繼續.

變數和屬性
在kotlin中,一切都是物件~

基本型別
integer float boolean等型別依然存在,不過是以物件存在.它們的工作方式與java十分相似,需要注意以下幾點:

數字型別不會自動轉型.例如不能給Double分配int型值

    val i: Int = 7
    val d: Double = i.toDouble()
複製程式碼

char不能直接作為一個數字來處理,需要轉換成數字

    val a : Char = 'c'
    val b : Int = a.toInt()
複製程式碼

位運算 java中使用的 || 或者 && kotlin中使用and or

    val willOr = FLAG1 or FLAG2
    val willAnd = FLAG1 and FLAG2
複製程式碼

字面可以寫明具體的型別,但是不是必須的,編譯器會自動解析型別

val i = 12 //as Int
val l = 3l //as Long
val f = 5f //as Float
val d = 3.5 //as Double
複製程式碼

一個String 可以像陣列那樣訪問,並且被迭代

val s = "test"
val t = s[2]//一個字元's'
//迭代
val o = "test"
for (b in o){
    print(t)
}
複製程式碼

變數
變數可簡單定義為 : val(不可變)和var(可變).但是不可變在kotlin是一個很重要的概念.

一個不可變物件意味著它在例項化之後就不能再去改變它的狀態了。如果你需要一個這個物件修改之後的版本,那就會再建立一個新的物件。這個讓程式設計更加具有健壯性和預估性。

在Java中,大部分的物件是可變的,那就意味著任何可以訪問它這個物件的程式碼都可以去修改它,從而影響整個程式的其它地方。不可變物件也可以說是執行緒安全的,因為它們無法去改變,也不需要去定義訪問控制,因為所有執行緒訪問到的物件都是同一個

一個重要的概念是:儘可能地使用val。除了個別情況(特別是在Android中,有很多類我們是不會去直接呼叫建構函式的),大多數時候是可以的。

如果我們需要使用更多的範型型別,則需要指定:

val a: Any = 23
val c: Context = activity
複製程式碼

屬性
沒有任何指定,屬性會預設使用getter和setter.

class Dog {
    val color : Int = 0
}
複製程式碼

當然也可以自定義set,get.

var color : Int = 3
    get() = field.toBigDecimal().intValueExact()
    set(value) {
        field = 3 + value
    }
複製程式碼

Anko來了

  • 主要目的是用來替換之前XMl的方式來使用程式碼生成UI佈局
  • Anko還包含了許多有幫助的函式和屬性來避免寫很多程式碼
  • 瞭解Anko的實現方式對學習kotlin有很大幫組

開始使用Anko
剛使用findviewbyid的可以用fins替換

    val recycler : RecyclerView  = find(R.id.recycler) 
複製程式碼

Anko還有一些別的實用功能:
例項化Intent,Activity之間的跳轉,Fragment的建立,資料庫的訪問,Alert的建立......。

擴充套件函式

擴充套件函式數是指在一個類上增加一種新的行為,甚至我們沒有這個類程式碼的訪問許可權。這是一個在缺少有用函式的類上擴充套件的方法。

在Java中,通常會實現很多帶有static方法的工具類。Kotlin中擴充套件函式的一個優勢是我們不需要在呼叫方法的時候把整個物件當作引數傳入。擴充套件函式表現得就像是屬於這個類的一樣,而且我們可以使用this關鍵字和呼叫所有public方法。

舉個例子,我們可以建立一個toast函式,這個函式不需要傳入任何context,它可以被任何Context或者它的子類呼叫,比如Activity或者Service:

fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {    
    Toast.makeText(this, message, duration).show()
}
複製程式碼

這個方法可以在Activity內部直接呼叫:

toast("Hello world!")
toast("Hello world!", Toast.LENGTH_LONG)
複製程式碼

擴充套件函式並不是真正地修改了原來的類,它是以靜態匯入的方式來實現的。擴充套件函式可以被宣告在任何檔案中,因此有個通用的實踐是把一系列有關的函式放在一個新建的檔案裡。

執行一個請求
如果只是執行一個簡單的api請求,我們可以不用任何非三方庫實現

class Request(val url : String) {
    fun run(){
        val jsonStr = URL(url).readText()
        Log.d("result",jsonStr)
    }
}
複製程式碼

眾所周知,在子執行緒中是不允許進行網路請求的,java的AsyncTask是非常醜陋的...diss一波...

Anko提供了非常簡單的DSL來處理非同步任務,它滿足大部分的需求。它提供了一個基本的async函式用於在其它執行緒執行程式碼,也可以選擇通過呼叫uiThread的方式回到主執行緒。在子執行緒中執行請求如下這麼簡單:

val url = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22"
        doAsync() {
            Request(url).run()
            uiThread { toast("Request") }
        }
複製程式碼

此時執行專案,檢視log,可以發現一個簡單請求已經實現了!
接著我們要把他使用json解析,轉換成實體類.

資料類 資料類是一種非常強大的類,它可以讓你避免建立Java中的用於儲存狀態但又操作非常簡單的POJO的模版程式碼。它們通常只提供了用於訪問它們屬性的簡單的getter和setter。定義一個新的資料類非常簡單:

data class Forecast(val date : Date , val temp : Float ,
                    val details : String) 
複製程式碼

轉換json到資料類

關於伴生物件Companion objects :
Kotlin允許我們去定義一些行為與靜態物件一樣的物件。儘管這些物件可以用眾所周知的模式來實現,比如容易實現的單例模式。我們需要一個類裡面有一些靜態的屬性、常量或者函式,我們可以使用companion object。這個物件被這個類的所有物件所共享,就像Java中的靜態屬性或者方法。

修改一下Request類:

class Request(val zipCode : String) {

    companion object {
        private val APP_ID = "15646a06818f61f7b8d7823ca833e1ce"
        private val URL = "http://api.openweathermap.org/data/2.5/" +"forecast/daily?mode=json&units=metric&cnt=7"
        private val COMPLETE_URL = "$URL&APPID=$APP_ID&q="
    }

    public fun execute() : ForecastResult{
        val jsonStr = URL(COMPLETE_URL + zipCode).readText()
        return Gson().fromJson(jsonStr,ForecastResult::class.java)
    }

    @Deprecated("使用execute替換")
    public fun run(){
        val jsonStr = URL(url).readText()
        Log.d("result",jsonStr)
    }
}
複製程式碼

資料類:

data class ForecastResult(val city: ResponseClasses.City,
                     val cnt: Int,
                     val cod: String,
                     val list: List<ResponseClasses.ForeCast>,
                     val message: Double) {


    data class ForeCast(
            val clouds: Int,
            val deg: Int,
            val dt: Int,
            val humidity: Int,
            val pressure: Double,
            val rain: Double,
            val speed: Double,
            val temp: Temp,
            val weather: List<Weather>
    )

    data class Temp(
            val day: Double,
            val eve: Double,
            val max: Double,
            val min: Double,
            val morn: Double,
            val night: Double
    )

    data class Weather(
            val description: String,
            val icon: String,
            val id: Int,
            val main: String
    )

    data class City(
            val coord: Coord,
            val country: String,
            val id: Int,
            val name: String,
            val population: Int
    )

    data class Coord(
            val lat: Double,
            val lon: Double
    )
}
複製程式碼

好累,先寫到這裡@_@

分享一首好音樂: Lo Que Siento - cuco
我們都是做夢的夢想家

相關文章