Android Jetpack MVVM封装及使用

MVVM架构图封装使用效果图demo参考

MVVM架构图

这张图清晰地展示了MVVM的三个模块:Activity / Fragment为View层,ViewModel + LiveData为ViewModel层,Repository(管理本地和远端数据)为Model层。

封装

理清了MVVM的层次,接下来尝试对其进行简单的封装。

1.BaseRepository

提取了生成Service类的方法apiService供子类使用。 提取了请求接口方法request,出现异常情况则throw,让ViewModel层处理。

abstract class BaseRepository {

protected fun apiService(tClass: Class): T {

return ApiClient.createService(tClass)

}

@Throws(Exception::class)

protected suspend fun request(block: suspend () -> BaseData): T {

val baseData = block()

if (baseData.errorCode == 0) {

if (baseData.data == null) {

throw Exception("baseData.data is null!")

}

return baseData.data

} else {

throw ApiException(baseData.errorCode, baseData.errorMsg)

}

}

}

2.BaseViewModel

提取了launch方法,可以一次调用多个接口;处理Model层抛出的异常。

abstract class BaseViewModel : ViewModel() {

private val _dataLoading = MutableLiveData()

val dataLoading: LiveData = _dataLoading

protected fun launch(

block: suspend () -> Unit,

error: suspend (Int) -> Unit = {

}

) {

viewModelScope.launch {

_dataLoading.value = true

try {

block.invoke()

} catch (e: Exception) {

when (e) {

is ApiException -> {

// TODO: use Toast to show errorMsg

error(e.code)

}

is ConnectException, is UnknownHostException, is SocketTimeoutException -> {

// TODO: use Toast to show exception message

Log.e("Exception", e.localizedMessage)

}

}

} finally {

_dataLoading.value = false

}

}

}

}

3.BaseVmActivity

提取viewModel字段及创建方法;添加viewModel的dataLoading字段的监听,实现统一的Loading管理。

abstract class BaseVmActivity : BaseActivity() {

protected val viewModel by lazy { ViewModelProvider(this).get(getVmClass()) }

private val loadingDialog by lazy { ContentLoadingDialog(this) }

abstract fun getVmClass(): Class

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

addObserver()

}

open fun addObserver() {

viewModel.dataLoading.observe(this) {

if (it) {

loadingDialog.showDialog()

} else {

loadingDialog.hideDialog()

}

}

}

}

使用

1.HomeRepository

添加hotkeys和banners方法,请求 玩Android 开放API 的搜索热词及首页banner接口。

class HomeRepository : BaseRepository() {

suspend fun hotkeys(): List {

return request {

apiService(HomeService::class.java).hotkeys()

}

}

suspend fun banners(): List {

return request {

apiService(HomeService::class.java).banners()

}

}

}

2.HomeViewModel

调用HomeRepository的hotkeys和banners方法(未处理banners接口返回数据,这里只做多个接口调用的演示),返回搜索热词列表,通过DataBinding自动将处理后的hotkeyText显示到TextView上。

class HomeViewModel : BaseViewModel() {

private val repository by lazy { HomeRepository() }

private val hotkeyList = MutableLiveData>()

private var _hotkeyText: LiveData = hotkeyList.distinctUntilChanged().map { createHotkeyText(it) }

val hotkeyText: LiveData = _hotkeyText

fun hotkeys() {

launch({

hotkeyList.value = repository.hotkeys()

repository.banners()

})

}

private fun createHotkeyText(list: List): String {

val text = StringBuilder()

for (key in list) {

text.append("${key.name}\n")

}

return text.toString()

}

}

3.MvvmActivity

利用DataBinding将viewModel赋值给viewmodel,实现数据绑定。

class MvvmActivity : BaseVmActivity() {

override fun getBinding(): ActivityMvvmBinding {

return ActivityMvvmBinding.inflate(layoutInflater).apply {

viewmodel = viewModel

lifecycleOwner = this@MvvmActivity

}

}

override fun getVmClass(): Class {

return HomeViewModel::class.java

}

}

效果图

接口请求太快了,loading都没有来得及显示。。。

demo

上面只展示了MVVM在Activity中的使用,demo里也有在Fragment中使用的代码。如需参考完整代码,请移步Github仓库:MVVM Demo

参考

【1】Android Jetpack系列之MVVM使用及封装

推荐链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: