Android Jetpack MVVM封装及使用

Posted crown23

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack MVVM封装及使用相关的知识,希望对你有一定的参考价值。

android Jetpack MVVM封装及使用

MVVM架构图


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

封装

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

1.BaseRepository

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

abstract class BaseRepository 
    protected fun <T> apiService(tClass: Class<T>): T 
        return ApiClient.createService(tClass)
    

	@Throws(Exception::class)
    protected suspend fun <T> request(block: suspend () -> BaseData<T>): 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<Boolean>()
    val dataLoading: LiveData<Boolean> = _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字段及创建方法;添加viewModeldataLoading字段的监听,实现统一的Loading管理。

abstract class BaseVmActivity<VDB : ViewDataBinding, VM : BaseViewModel> : BaseActivity<VDB>() 
    protected val viewModel by lazy  ViewModelProvider(this).get(getVmClass()) 

    private val loadingDialog by lazy  ContentLoadingDialog(this) 

    abstract fun getVmClass(): Class<VM>

    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

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

class HomeRepository : BaseRepository() 
    suspend fun hotkeys(): List<HotkeyModel> 
        return request 
            apiService(HomeService::class.java).hotkeys()
        
    

    suspend fun banners(): List<Any> 
        return request 
            apiService(HomeService::class.java).banners()
        
    

2.HomeViewModel

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

class HomeViewModel : BaseViewModel() 
    private val repository by lazy  HomeRepository() 

    private val hotkeyList = MutableLiveData<List<HotkeyModel>>()

    private var _hotkeyText: LiveData<String> = hotkeyList.distinctUntilChanged().map  createHotkeyText(it) 
    val hotkeyText: LiveData<String> = _hotkeyText

    fun hotkeys() 
        launch(
            hotkeyList.value = repository.hotkeys()
            repository.banners()
        )
    

    private fun createHotkeyText(list: List<HotkeyModel>): String 
        val text = StringBuilder()
        for (key in list) 
            text.append("$key.name\\n")
        
        return text.toString()
    

3.MvvmActivity

利用DataBindingviewModel赋值给viewmodel,实现数据绑定。

class MvvmActivity : BaseVmActivity<ActivityMvvmBinding, HomeViewModel>() 
    override fun getBinding(): ActivityMvvmBinding 
        return ActivityMvvmBinding.inflate(layoutInflater).apply 
            viewmodel = viewModel
            lifecycleOwner = this@MvvmActivity
        
    

    override fun getVmClass(): Class<HomeViewModel> 
        return HomeViewModel::class.java
    

效果图

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

demo

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

参考

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

以上是关于Android Jetpack MVVM封装及使用的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack系列之MVI架构

Android Jetpack ROOM 的Dao返回LiveData<Bean>封装及Bean普通的区别

是让人耳目一新的 Jetpack MVVM 精讲啊

Android 基于Jetpack的MVVM架构入门指南

年薪百万之让人耳目一新的 Jetpack MVVM 精讲

开源100% Kotlin 的 Android Jetpack mvvm 项目!