推薦一個Kotlin專案
標題之所有沒有使用優秀、優質等華麗的辭藻修飾,是因為這個專案是本人在學習Kotlin過程中用來練手的,不敢在給各位前輩和大神面前班門弄斧,自取其辱,況且github上的玩Android客戶端已經有很多個版本了,我也只能望其項背
自Google在2017的I/O大會上宣佈Android支援Kotlin,到現在Kotlin語言已受到大批Android開發者的追捧,許多大廠已經使用純Kotlin進行Android開發
2018的I/O大會又釋出可跨平臺的UI框架Flutter ,支援在Android和iOS平臺執行
這還沒完沒了了...
大勢所趨吧,不得不學...
專案簡介
上圖,把四張拼一起了

- 基於Jetpack(包含livedata、lifecycle、paging、room)元件採用 MVVM架構,Jetpack元件的使用方法在這裡不做說明
- 元件化開發,module之間跳轉使用阿里的ARouter路由框架
- 資料來源於 hongyang玩Android開放API ,聚集了鴻洋、郭霖等諸多大神的公眾號文章和高質量的開源專案推薦介紹
- 你不妨把這個app當做你的的掌上開源社群使用
專案使用到的開源庫
- kolint工具庫anko
- 網路請求okhttp
- 網路請求Retrofit
- 非同步框架Rxjava2
- 依賴注入Dagger2
- 阿里路由框架ARouter
- 圖片載入Glide
- 日誌列印KLog
- 可翻頁的RecyclerView
- 側滑刪除SwipeDelMenuLayout
- 流式佈局FlowLayout
- 輪播圖控制元件banner
專案架構解析
專案分為四個module
app,App的殼
module_base,公共庫
module_user、module_wan,業務模組

既然是元件化開發,那各個業務模組肯定可以單獨執行
//根據變數isModule判斷是作為依賴library還是單獨的application if (isModule) { apply plugin: 'com.android.library' } else { apply plugin: 'com.android.application' } sourceSets { main { //根據變數isModule使用不同資料夾的程式碼 if (isModule) { manifest.srcFile 'src/main/AndroidManifest.xml' java { //去除指定資料夾程式碼 exclude '*module' } } else { //這裡面只用一個Activity,重當殼Activity java.srcDirs 'src/main/java', 'src/main/module/java' manifest.srcFile 'src/main/module/AndroidManifest.xml' } } }
app
它是app的殼,裡面只有一個MainActivity,它負責整合所需要的業務模組

dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':module_base') kapt kaptLibs if (isModule) { //依賴業務module implementation project(':module_user') implementation project(':module_wan') } }
module_base
作為公共庫,存放base和公用程式碼,其它的module都要依賴它

module_wan和module_user
主要的業務

Kotlin的一些特性在專案中的運用
擴充套件函式
//給ImageView新增一個擴充套件函式,就當做ImageView有了一個load方法 //ImageView作為接受者型別,只有ImageView和其子類能呼叫該方法 fun ImageView.load(url: Any) { //this代表接受這物件 Glide.with(this).load(url).into(this) } var imageView: ImageView = ... //直接使用ImageView物件呼叫load方法 imageView.load(url)
以前使用工具類必須要傳一個型別為ImageView的引數,現在直接用ImageView呼叫擴充套件方法是不是簡單了很多
空判斷
override fun setTitle(title: CharSequence?) {//這個?表示該變數可以為null //? 表示如果toolbar不為空才執行後面的程式碼,給其屬性title賦值 toolbar?.title = title }
想想以前程式碼裡面到處都是 if(... != null)類似的模板程式碼都陣痛
函式預設引數
fun <VH : RecyclerView.ViewHolder, A : Adapter<VH>> RecyclerView.init(adapter: A, //layoutManager有一個預設值LinearLayoutManager(context) layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(context)) { this.layoutManager = layoutManager this.adapter = adapter } //只傳了一個引數,layoutManager使用預設值 recyclerView.init(adapter) //傳了兩個引數 flowLayout.init(flowAdapter, FlowLayoutManager())
如果函式有多個引數預設的時候,我們只想某幾個引數使用其預設值,為了不引起混亂,我們可以根據引數名傳參,隨便寫個Demo說明一下
fun main() { //呼叫函式,如果不寫 c = 預設是b = test(1, c = 10) } fun test(a: Int, b: Int = 2, c: Int = 3, d: Int = 4) { ... }
函數語言程式設計
一個函式作為另一個函式的引數傳遞
fun <D, T : HttpResult<D>> Observable<T>.subscribeBy(onResponse: (D?) -> Unit, onFailure: (String) -> Unit) = subscribe({ if (it.errorCode == 0) { //函式呼叫 onResponse(it.data) } else { //函式呼叫 onFailure(it.errorMsg) } }, { onFailure(it.message!!) })
onResponse引數接收一個引數型別為D,無返回值的方法;onFailure引數接收一個引數型別為String,無返回值的方法。如果定義一個函式無返回值,那麼它的返回值就是Unit,不要問我為什麼,這就是語法,約定俗成
Api.getKnowledgeArticle(page - 1, typeId).io_main().subscribeBy( { onResponse(it?.datas) },//第一個引數,it就是型別為D的引數 { onResponse(null) Log.d(TAG,it) }//第二個引數,it就是型別為String的引數 ).add()
是不是很懵逼,因為你可能不懂lambda表示式的使用
關於Kotlin的特性還用很多,例如when表示式、屬性委託、字串模板、型別自動轉換、協程等等,這裡就不一一講解了,講不完的,現在不熬夜
進階之路
因每個人學習方法不同,僅供參考
- 先在 Kotlin 語言中文站 跟著教程敲一遍,語法你總得先基本掌握吧
- 多看幾個star很多的Kotlin開源專案,最好完全敲一遍,裡面還會很有很多你在官網上可能沒看到的東西
大神們的程式碼也會讓你有很多意想不到的收穫,起碼告訴你,你的程式碼Low爆了,會讓你有種從此回家帶孩子吧的衝動
專案中使用到了很多開源庫,在此向所有對開源做出過貢獻的各位大神表示感謝,正是有你們的開源共享,我們這些菜鳥的技術才能有所提升,也是你們用最美的語言,推動了科技的進步
附上本專案地址 Github傳送門
Apk玩Android下載地址 https://haoshi.co/wanandroid.apk

掃碼下載