真香!Kotlin+MVVM+LiveData+协程 打造 Wanandroid!

关注 秉心说,公众号后台回复 玩安卓 便可获取 Wanandroid 安装包。java

Wanandroid 是鸿洋鸿大大的安卓开源知识网站,包含最新博文,最新项目,经常使用工具,公众号文章收录等等功能,同时也开源了全部 API 接口,方便你们打造本身的 Wanandroid 客户端。Github 上关于 Wanandroid 的客户端也层出不穷,Java的,Kotlin 的,Flutter 的,Mvp 的,MVMM 的,各类各样,可是还没看到 Kotlin+MVVM+LiveData+协程 版本的,加上最近正在看 MVVM 和 LiveData,就着手把我以前写的 Mvp 版本的 Wanandroid 改形成 MVVM,项目地址 。注意,mater 分支是年久失修的 Mvp 版本,不必定保证能够运行。mvvm-kotlin 分支是最新代码。android

关于 MVVM,你们应该也比较熟悉了,上一张 MVVM 经典架构图:git

Model-View-ViewModelView 指绿色的 Activity/Fragment,主要负责界面显示,不负责任何业务逻辑和数据处理。Model 指的是 Repository 包含的部分,主要负责数据获取,来组本地数据库或者远程服务器。ViewModel 指的是图中蓝色部分,主要负责业务逻辑和数据处理,自己不持有 View 层引用,经过 LiveDataView 层发送数据。Repository 统一了数据入口,无论来自数据库,仍是服务器,统一打包给 ViewModel ,我在项目中并无使用数据库,而是使用缓存代替。github

除了 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 接口。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 进行绑定,上面代码中的 mLoginUsererrMsg 就是 ViewModel 层 “发射” 过来的数据。关于数据绑定,我并无使用 DataBinding,这个纯粹是我的喜爱了,我只是不喜欢 DataBinding 带来的代码不易读。

相对 Mvp 繁多的接口来讲,我的感受 Mvvm 的数据流更加清晰。搭配 Kotlin 和协程的使用,进一步简化代码。下面是一些项目截图:

项目地址点这个: 传送门,记得切换到 mvvm-kotlin 分支 ,欢迎带来 star 和 issue 丢过来 !

推荐一下个人另外一个应用,Box —— 个人开发助手,添加了查看 logcat 的功能。

最后,也欢迎你们关注个人公众号 秉心说,话说公号关注人数还没掘金多,后续会继续 《走进 JDK 系列》以及 Android 相关知识的分享,欢迎你们扫码关注!有任何关于 Java/Android 的问题也能够加个人我的微信 bingxinshuo_

公众号后台回复 玩安卓 便可获取 Wanandroid 安装包。

文章首发微信公众号: 秉心说 , 专一 Java 、 Android 原创知识分享,LeetCode 题解,欢迎关注!

相关文章
相关标签/搜索