Wanandroid 是鴻洋鴻大大的安卓開源知識網站,包含最新博文,最新專案,常用工具,公眾號文章收錄等等功能,同時也開源了所有 API 介面,方便大家打造自己的 Wanandroid 客戶端。Github 上關於 Wanandroid 的客戶端也層出不窮,Java的,Kotlin 的,Flutter 的,Mvp 的,MVMM 的,各種各樣,但是還沒看到 Kotlin+MVVM+LiveData+協程 版本的,加上最近正在看 MVVM 和 LiveData,就著手把我之前寫的 Mvp 版本的 Wanandroid 改造成 MVVM,專案地址 。注意,mater
分支是年久失修的 Mvp
版本,不一定保證可以執行。mvvm-kotlin
分支是最新程式碼。
關於 MVVM,大家應該也比較熟悉了,上一張 MVVM 經典架構圖:
Model-View-ViewModel
,View
指綠色的 Activity/Fragment
,主要負責介面顯示,不負責任何業務邏輯和資料處理。Model
指的是 Repository
包含的部分,主要負責資料獲取,來組本地資料庫或者遠端伺服器。ViewModel
指的是圖中藍色部分,主要負責業務邏輯和資料處理,本身不持有 View
層引用,通過 LiveData
向 View
層傳送資料。Repository
統一了資料入口,不管來自資料庫,還是伺服器,統一打包給 ViewModel
,我在專案中並沒有使用資料庫,而是使用快取代替。
除了 MMVM
以外,我用 協程
代替了 RxJava
。這裡先不論協程和 RxJava 孰優孰劣,只是用慣了 RxJava,協程的確會給你耳目一新的感覺,用同步的方式寫非同步程式碼。在 Java 中並沒有協程的概念,Kotlin 中在編譯期實現了協程,通過類似狀態機的實現。協程可以看做是輕量級的執行緒,不會存在上下文切換的帶來的效能損耗,理論上是比執行緒效率更高的。
下面以登入頁面 LoginActivity
為例,看一下資料流程。
Model
@POST("/user/login")
fun login(@Field("username") userName: String, @Field("password") passWord: String): Deferred<WanResponse<User>>
複製程式碼
這是登入 Api 介面。
class LoginRepository : BaseRepository() {
suspend fun login(userName: String, passWord: String): WanResponse<User> {
return apiCall { WanRetrofitClient.service.login(userName, passWord).await() }
}
}
複製程式碼
LoginRepository
中定義具體的登入邏輯,通過 Retrofit
呼叫登入介面,返回 WanResponse<User>
。注意,要在協程中使用,所以定義為 suspend
方法。
ViewModel
class LoginViewModel : BaseViewModel() {
val mLoginUser: MutableLiveData<User> = MutableLiveData()
val errMsg: MutableLiveData<String> = MutableLiveData()
private val repository by lazy { LoginRepository() }
fun login(userName: String, passWord: String) {
launch {
val response = withContext(Dispatchers.IO) { repository.login(userName, passWord) }
executeResponse(response, { mLoginUser.value = response.data }, { errMsg.value = response.errorMsg })
}
}
}
複製程式碼
LoginViewModel
持有 LoginRepository
,並通過它執行具體登入邏輯,這一塊使用協程執行。返回結果通過 executeResponse()
方法處理,這是我自己封裝的方法:
suspend fun executeResponse(response: WanResponse<Any>, successBlock: suspend CoroutineScope.() -> Unit,
errorBlock: suspend CoroutineScope.() -> Unit) {
coroutineScope {
if (response.errorCode == -1) errorBlock()
else successBlock()
}
}
複製程式碼
Kotlin 的一些函數語言程式設計語言特性會給我們的開發帶來一些便利。executeResponse()
提供了統一的響應錯誤處理。
View
mViewModel.apply {
mLoginUser.observe(this@LoginActivity, Observer {
dismissProgressDialog()
startActivity(MainNormalActivity::class.java)
finish()
})
errMsg.observe(this@LoginActivity, Observer {
dismissProgressDialog()
it?.run { toast(it) }
})
}
複製程式碼
最後就是 LoginActivity
代表的 View 層了,View 層和 ViewModel 層通過 LiveData 進行繫結,上面程式碼中的 mLoginUser
和 errMsg
就是 ViewModel 層 “發射” 過來的資料。關於資料繫結,我並沒有使用 DataBinding
,這個純粹是個人喜好了,我只是不喜歡 DataBinding 帶來的程式碼不易讀。
相對 Mvp 繁多的介面來說,個人感覺 Mvvm 的資料流更加清晰。搭配 Kotlin 和協程的使用,進一步簡化程式碼。下面是一些專案截圖:
專案地址點這個: 傳送門,記得切換到 mvvm-kotlin
分支 ,歡迎帶來 star 和 issue 丟過來 !
推薦一下我的另一個應用,Box —— 我的開發助手,新增了檢視 logcat 的功能。
最後,也歡迎大家關注我的公眾號 秉心說,話說公號關注人數還沒掘金多,後續會繼續 《走進 JDK 系列》以及 Android 相關知識的分享,歡迎大家掃碼關注!有任何關於 Java/Android 的問題也可以加我的個人微信 bingxinshuo_
。
文章首發微信公眾號:
秉心說
, 專注 Java 、 Android 原創知識分享,LeetCode 題解,歡迎關注!