在前一篇中,介紹了 KtArmor—MVVM 簡單的使用方法,可是這每每不是所有。git
在持續迭代、維護下,發現功能越寫越多,也相應複雜起來。github
因此後續,我儘量編寫詳細 說明文檔,而且在源碼編寫 註釋api
廢話很少說,進入正文。網絡
回到上文所說的 Login 示例,咱們在 LoginViewModel,經過quickLaunch DSL 方式,發起網絡請求。以下代碼所示:框架
class LoginViewModel : BaseViewModel<LoginRepository>() {
val loginData = MutableLiveData<LoginRsp>()
fun login(account: String, password: String) {
...省略其餘代碼
// DSL 方式發起 網絡請求
quickLaunch<LoginRsp> {
onStart { showLoading() }
request { repository.login(account, password) }
onSuccess { loginData.value = it }
}
}
}
複製代碼
quickLaunch 方法,需傳入範型( 返回值類型),即調用 repository.login(account, password) 返回值類型, 且必須實現 KResponse 接口,以下代碼所示:ide
@POST(API.LOGIN)
suspend fun login(@Query("username") username: String, @Query("password") password: String): BaseResponse<LoginRsp>
複製代碼
因爲 quickLaunch DSL 方式默認實現了 Success,Failure 邏輯處理,而且進行相應回調。因此 Retrofit 的 api service 返回的 BaseResponse,必須實現 KResponse 接口。post
data class BaseResponse<T>(var data: T?,
var errorCode: Int = -1,
var errorMsg: String = "") : KResponse<T> {
override fun isSuccess(): Boolean = errorCode == 0
override fun getKData(): T? = data
override fun getKMessage(): String? = errorMsg
}
複製代碼
以上是參考代碼,根據後臺接口返回的類型,新建一個 基類 Response(BaseResponse),實現 KResponse 接口,而且實現對應的方法學習
其中 executeRsp,execute 默認實現了 默認的處理邏輯,以下所示優化
/** * 全局默認實現, 可根據自身業務 重寫execute方法 * @param error 如有錯誤的回調, 默認getKMessage(), 不然返回 Setting.MESSAGE_EMPTY * @param successResponse 成功的回調, 默認是返回 KResponse<T> */
fun executeRsp(successResponse: ((KResponse<T>) -> Unit)?, error: ((String) -> Unit)? = null) {
if (this.isSuccess()) {
successResponse?.invoke(this)
return
}
(this.getKMessage() ?: Setting.MESSAGE_EMPTY).let {
error?.invoke(it) ?: Toasts.show(it)
}
}
/** * 全局默認實現, 可根據自身業務 重寫execute方法 * @param success 成功的回調, 默認是返回 getKData() * @param error 如有錯誤的回調, 默認getKMessage(), 不然返回 Setting.MESSAGE_EMPTY */
fun execute(success: ((T?) -> Unit)?, error: ((String) -> Unit)? = null) {
if (this.isSuccess()) {
success?.invoke(this.getKData())
return
}
(this.getKMessage() ?: Setting.MESSAGE_EMPTY).let {
error?.invoke(it) ?: Toasts.show(it)
}
}
複製代碼
以 execute 爲例,默認是 根據 isSuccess
判斷是否成功,而且 回調到 quickLaunch 方法的 onSuccess、onFailure 方法。開發者能夠根據自身需求,對 execute/executeRsp 方法重寫。ui
你覺得這樣就完事了嗎?
通常狀況下,咱們獲取了 repository 返回的數據,在 onSuccess 方法處理本身的業務邏輯。
而後 遇到異常,會進行以下操做:
toast
顯示 message以下代碼所示:
quickLaunch<LoginRsp> {
request { repository.login(account, password) }
onSuccess { loginSuccessData.value = it }
onFailure { loginFailData.value = it }
onException { loginExceptionLiveData = it }
}
複製代碼
因爲 Activity 是經過觀察 ViewModel 中 liveData 數據變化,進而作 請求成功,請求失敗 等邏輯處理。
因此首先想到是 新增 三個 LiveData,來通知 Activity,可是每次請求,都須要如此操做,這時候須要封裝一下了。
KtArmor-MVVM, 嘗試引入一個 複合 LiveData—— CommonLiveData,解決上面問題, 所謂 複合,本質就是 CommonLiveData,裏面包含 兩個LiveData,以下代碼所示:
class CommonLiveData<T> : MutableLiveData<T>() {
val errorLiveData = MutableLiveData<String>()
... 省略其餘
}
複製代碼
在ViewModel 中 使用方式以下
val loginData = CommonLiveData<LoginRsp>()
// 看這裏 ^^^^
quickLaunch<LoginRsp> {
request { repository.login(account, password) }
onSuccess { loginData.value = it }
onFailure { loginData.failureMessage = it }
onException { loginData.exception = it }
}
/** * 等同上面 quickLaunch */
superLaunch(loginData) {
request { repository.login(account, password) }
}
/** * 等同上面 superLaunch */
superLaunchRequest(loginData) { repository.login(account, password) }
複製代碼
在原有基礎上,MutableLiveData,切換成 CommonLiveData
而且新增一個 superLaunch DSL 方法,簡化了 quickLaunch DSL 方法 的賦值操做
固然 你也能夠根據自身業務,重寫 onSuccess, onFailure, onException 等方法。
而後咱們再來看看 Activity,代碼上,就更加方便簡單明瞭。
class LoginActivity : AppCompatActivity(), IMvmActivity {
...省略其餘代碼
override fun dataObserver() {
// 正常 MutableLiveData 監聽
viewModel.loginData.observe(this, Observer {
toast("登陸成功")
})
// CommonLiveData 監聽
quickObserve(loginViewModel.loginData) {
onSuccess {
toast("登陸成功")
}
onFailure { message ->
toast(message)
}
onException { throwable ->
toast(R.string.unkown_error)
logd(msg)
}
}
/** * CommonLiveData 監聽, 等同上面, 只監聽 Success 狀況 * onSuccess: 自定義實現 * onFailure: 默認 toast message (viewModel 傳遞過來的 message) * onException: 默認 toast "未知異常"(固定), 打印 log */
quickObserveSuccess(loginViewModel.loginData) {
toast("登陸成功")
}
}
}
複製代碼
仍是以 Login 示例,咱們在 LoginActivity 中,須要 observe, LoginViewModel 中的 loginData,來獲取 請求成功後的數據。
如果 使用了 CommonLiveData,則咱們只需調用 quickObserve 或 quickObserveSuccess,便可監聽到 ViewModel 傳遞過來的數據,進行相應的處理。
具體方法說明,都在上面代碼註釋所示。
看到這裏,可能有小夥伴會說了,你的默認實現,不符合個人業務,不喜歡,想要修改,怎麼辦。
沒問題!
KtArmor-MVVM 提供對應接口,給開發者進行自定義擴展
class MyActivityActuator : IActivityActuator {
override fun <R> success(mvmView: IMvmView, data: R?) {
}
override fun failure(mvmView: IMvmView, message: String?) {
}
override fun exception(mvmView: IMvmView, throwable: Throwable?) {
}
}
複製代碼
新建 MyActivityActuator, 而且實現 IActivityActuator 接口,自定義 quickObserve 默認處理邏輯。
ViewModel ,也是同理。實現 ILiveDataActuator 接口,自定義 superLaunch 默認處理邏輯
class MyLiveDataActuator : ILiveDataActuator() {
override fun <R> success(liveData: CommonLiveData<R>, data: R?) {
}
override fun <R> failure(liveData: CommonLiveData<R>, message: String?) {
}
override fun <R> exception(liveData: CommonLiveData<R>, throwable: Throwable?) {
}
}
複製代碼
最後別忘了,須要 配置到 KtArmor 中,這樣纔會生效!
class BaseApplication : Application() {
override fun onCreate() {
super.onCreate()
// KtArmor 相關配置
with(KtArmor){
configActivityActuator(MyActivityActuator())
configLiveDataActuator(MyLiveDataActuator())
}
}
}
複製代碼
代碼總體實現上,相對簡單,遵循開源框架的 三部曲,使得框架 可全局配置,可局部配置。
後續想到更好的方案,在進行優化,
不知大家意向如何? 期待小夥伴們更好方案 : )
KtArmor-MVVM
框架是一款小而美的框架,也是我我的經驗的積累, 總結,但願你們喜歡。
若是你有更好的建議歡迎 pr,issues 一塊兒交流學習。
若有不妥, 望各位大佬指出。
下次再見