对基础框架进行模块分离, 分为
MVVM Library
--MVVM Navigation Library
--MVVM Network Library
可基于业务需求使用MVVM Library
、MVVM Navigation Library
、MVVM Network Library
已开发一键生成代码模板, 创建适用于本框架的Activity和Fragment. 具体查看AlvinMVVMPlugin_4_3
具体使用请查看library中的注释,已经非常清楚. 一定要看 Demo
To get a Git project into your build:
Step 1. Add the JitPack repository to your build file
Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Step 2. Add the dependency
dependencies {
// MVVM 基类
implementation 'com.github.Chen-Xi-g.MVVMFramework:mvvm_framework:Tag'
// MVVM Network 只负责网络处理
implementation 'com.github.Chen-Xi-g.MVVMFramework:mvvm_network:Tag'
// MVVM Navigation 组件抽离
implementation 'com.github.Chen-Xi-g.MVVMFramework:mvvm_navigation:Tag'
}
随着
Jetpack
的完善,对于开发者来说,MVVM
显得越来越高效与方便。对于使用
MVVM
的公司来说,都有一套自己的MVVM
框架,但是我发现有些只是对框架进行非常简单的封装,导致在开发过程中会出现很多没必要的冗余代码。这篇文章主要就是分享如何从0搭建一个高效的
MVVM
框架。
在封装之前,要确定自己需要封装的功能,列如常用的Activity
、Fragment
、LiveData
、ViewModel
、Navigation
、以及其他的Widget
。
所以你要在开始开发之前确定好包的分包结构。下面是我对MVVM
框架的分包结构。
从上图可以看到每次包都是非常明确
base
包下封装了MVVM
的基础组件activity
实现DataBinding + ViewModel
的封装,以及一些其他功能adapter
实现DataBinding + Adapter
的封装fragment
实现DataBinding + ViewModel
的封装,以及一些其他功能livedata
实现LiveData
的基础功能封装,如非空返回值navigation
实现导航的统一处理view_model
实现BaseViewModel
的处理
callback
包下封装了组件的回调接口help
包下封装了组件的辅助类manager
包下封装了对于组件的管理
通过上面的框架结构,现在已经有了明确的目标。
这时候需要对
BaseActivity
的功能进行抽离,避免所有的功能都写在一个类中,导致维护与扩展成本太高。以下只展示Activity的具体实现内容,注释已经非常明确。
在结束后,你会得到下图结构的Activity
。
AbstractActivity
是Activity
的抽象基类,这个类里面的方法适用于全部Activity
的需求。 该类中封装了所有Activity必须实现的抽象方法。BaseActivity
封装了基础的Activity
功能,主要用来初始化Activity
公共功能:DataBinding
的初始化、沉浸式状态栏、AbstractActivity
抽象方法的调用、屏幕适配、空白区域隐藏软键盘。具体功能可以自行新增。BaseDialogActivity
只负责显示Dialog Loading
弹窗,一般在提交请求或本地流处理时使用。也可以扩展其他的Dialog
,比如时间选择器之类。BaseContentViewActivity
是对布局进行初始化操作的Activity
,他是我们的核心。这里处理了每个Activity
的每个状态的布局,一般情况下有:TitleLayout
公共标题ContentLayout
主要的内容布局,使我们需要程序内容的主要容器。ErrorLayout
当网络请求发生错误,需要对用户进行友好的提示。LoadingLayout
正在加载数据的布局,给用户一个良好的体验,避免首次进入页面显示的布局没有数据。
BaseVMActivity
实现ViewMode
的Activity
基类,通过泛型对ViewModel
进行实例化。并且通过BaseViewModel
进行公共操作。BaseMVVMActivity
所有Activity
最终需要继承的MVVM
类,通过传入DataBinding
和ViewModel
的泛型进行初始化操作,在构造参数中还需要获取Layout
布局BaseListActivity
适用于列表的Activity
,分页操作、上拉加载、下拉刷新、空布局、头布局、底布局封装。
根据你的需要进行不同的封装,我比较倾向于和Activity
具有相同功能的封装,也就是Activity
封装的功能我Fragment
也要有。这样在使用Navigation
的时候可以减少Activity
和Fragment
的差异。这里直接参考Activity的封装
每个项目中肯定会有列表的页面,所以还需要对Adapter
进行DataBinding
适配,这里使用的Adapter是BRVAH。
abstract class BaseBindingListAdapter<T, DB : ViewDataBinding>(
@LayoutRes private val layoutResId: Int
) : BaseQuickAdapter<T, BaseViewHolder>(layoutResId) {
abstract fun convert(holder: BaseViewHolder, item: T, dataBinding: DB?)
override fun convert(holder: BaseViewHolder, item: T) {
convert(holder, item, DataBindingUtil.bind(holder.itemView))
}
}
LiveData
在使用的时候会出现数据倒灌的情况,用简单的话来描述数据倒灌:A订阅1月1日新闻信息,B订阅1月15日新闻信息,但是B在1月15日同时收到了1月1日的信息,这明显不符合我们生活中的逻辑,所以需要对LiveData
进行封装,详细的可以查看KunMinX
的**UnPeek-LiveData**。
通过重写 FragmentNavigator
将原来的 FragmentTransaction.replace()
方法替换为 hide()/Show()
在BaseViewModel
中封装一个网络请求需要用的LiveData
,下面是一个简单的示例
open class BaseViewModel : ViewModel() {
// 默认的网络请求LiveData
val httpCallback: HttpCallback by lazy { HttpCallback() }
inner class HttpCallback {
/**
* 请求发生错误
*
* String = 网络请求异常
*/
val onFailed by lazy { StringLiveData() }
/**
* 请求开始
*
* LoadingEntity 显示loading的实体类
*/
val beforeNetwork by lazy { EventLiveData<LoadingEntity>() }
/**
* 请求结束后框架自动对 loading 进行处理
*
* false 关闭 loading or Dialog
* true 不关闭 loading or Dialog
*/
val afterNetwork by lazy { BooleanLiveData() }
}
}
在封装以上基础组件时,需要自定义回调的接口统一存放到callback
目录下
大部分的Activity
和Fragment
样式基本相同,比如布局中的TitleLayout
、LoadingLayout
这些都是统一样式。所以可以封装全局的辅助类来对Activity中的属性进行抽离。
- 定义接口
ISettingBaseActivity
添加抽离的方法,并且赋于默认值。 - 定义接口
ISettingBaseFragment
添加抽离的方法,并且赋于默认值。 - 创建
ISettingBaseActivity
和ISettingBaseFragment
的实现类,进行默认的自定义操作。 - 创建
GlobalMVVMBuilder
进行赋值
通过Lifecycle
结合AppManager
对Activity的进出栈管理。
该框架参考以下优秀开源项目,特此鸣谢. 不分先后按首字母排序.
- AndroidUtilCode 安卓工具类库
- AVLoadingIndicatorView 加载Loading动画
- BRVAH 万能Adapter
- DKVideoPlayer 安卓视频播放器
- JetPackMvvm 基于MVVM模式集成JetPack玩Android项目
- material-dialogs 一个漂亮、流畅、可扩展的对话框API,适用于Kotlin和Android。
- RecyclerViewDivider 一个为RecyclerView配置分隔符的库。
- SmartRefreshLayout Android智能下拉刷新框架
- saf-logginginterceptor Android项目中,OKHttp的日志的拦截器
- Square Square公司的 Retrofit + OkHttp + Moshi
- UnPeek-LiveData 解决LiveData数据倒灌
- 优客API 免费的API接口服务
具体的实现过程已经在Github开源,并且有非常完整的注释,后续将会对Sample
完善。
如果不想关注具体的实现,直接通过Gradle
引入MVVM
的依赖即可使用。
如果你感觉对你有用的话请点一下Star吧,而且你还可以打赏一波(If you feel useful to you, please click Star, or you can reward it.)
QQ: 1217056667
邮箱(Email): [email protected]
Copyright (c) 2022 忞鹿
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.