kmvvm
Gitee 地址:kmvvm
Github 地址:CHANGE LOG
技术要点
-
支持Flow+Retrofit+OkHttp实现链式http请求
-
支持Rxjava+Retrofit+OkHttp实现链式http请求
-
封装基类:BaseActivity、BaseVMActivity、BaseFragment、BaseVMFragment、RecycleAdapter、BaseViewModel
-
封装工具扩展类:CalendarExt、ContextExt、DateExt、EditTextExt、GsonExt、RxJavaExt、StringExt、SnackbarExt
-
引入LifeCycle,将ViewModel和Activity的生命周期绑定在一起
-
将在Application中初始化移至到ContentProvider中,从而不用封装BaseApplication
-
APT(编译时注解)封装注解:Title、OnClickFirstDrawable、OnClickFirstText、OnClickSecondDrawable、OnClickSecondText、Prefs、PrefsField、StatusBar、ObserverError、Adapter、GlobalConfig、ServiceApi
最低兼容:21
Gradle
1. 在Project的build.gradle中添加
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
2. 在app的build.gradle的添加
apply plugin: 'kotlin-kapt' // 使用 kapt 注解处理工具
3. 在app的build.gradle的android下添加
buildFeatures {
viewBinding = true
}
4. 添加依赖
Gitee
implementation "com.gitee.catchpig.kmvvm:mvvm:last_version"
kapt "com.gitee.catchpig.kmvvm:compiler:last_version"
Github
implementation "com.github.catchpig.kmvvm:mvvm:last_version"
kapt "com.github.catchpig.kmvvm:compiler:last_version"
使用
1. 配置全部参数
interface IGlobalConfig {
/**
* 标题栏高度
* @return Int
*/
@DimenRes
fun getTitleHeight(): Int
/**
* 标题栏的返回按钮资源
* @return Int
*/
@DrawableRes
fun getTitleBackIcon(): Int
/**
* 标题栏背景颜色
* @return Int
*/
@ColorRes
fun getTitleBackground(): Int
/**
* 标题栏文本颜色
* @return Int
*/
@ColorRes
fun getTitleTextColor(): Int
/**
* 标题栏下方是否需要横线
* @return Boolean
*/
fun isShowTitleLine(): Boolean
/**
* 标题栏下方横线颜色
* @return Int
*/
@ColorRes
fun getTitleLineColor(): Int
/**
* loading的颜色
* @return Int
*/
@ColorRes
fun getLoadingColor(): Int
/**
* loading的背景颜色
* @return Int
*/
@ColorRes
fun getLoadingBackground(): Int
/**
* RecyclerView的空页面ViewBinding
* @param parent ViewGroup
* @return ViewBinding
*/
fun getRecyclerEmptyBanding(parent: ViewGroup): ViewBinding
/**
* 刷新每页加载个数
* @return Int
*/
fun getPageSize():Int
/**
* 刷新起始页的index(有些后台设置的0,有些后台设置1)
*/
fun getStartPageIndex():Int
}
- 实现IGlobalConfig接口,并在实现类上加上注解GlobalConfig
使用示例:
@GlobalConfig
class MvvmGlobalConfig : IGlobalConfig {
override fun getTitleHeight(): Int {
return R.dimen.title_bar_height
}
override fun getTitleBackIcon(): Int {
return R.drawable.back_black
}
override fun getTitleBackground(): Int {
return R.color.colorPrimary
}
override fun getTitleTextColor(): Int {
return R.color.white
}
override fun isShowTitleLine(): Boolean {
return true
}
override fun getTitleLineColor(): Int {
return R.color.color_black
}
override fun getLoadingColor(): Int {
return R.color.color_black
}
override fun getLoadingBackground(): Int {
return R.color.white
}
override fun getRecyclerEmptyBanding(parent: ViewGroup): ViewBinding {
return LayoutEmptyBinding.inflate(LayoutInflater.from(parent.context), parent, false)
}
override fun getPageSize(): Int {
return 16
}
override fun getStartPageIndex(): Int {
return 1
}
}
2. Activity
-
使用MVVM的继承BaseVMActivity
-
不使用MVVM的继承BaseActivity
2.1 标题注解使用
使用示例
@Title(R.string.child_title) class ChildActivity : BaseVMActivity<ActivityChildBinding, ChildViewModel>()
2.2 状态栏注解使用
使用示例
@StatusBar(hide = true) class FullScreenActivity : BaseActivity<ActivityFullScreenBinding>()
3. Fragment
- 使用MVVM的继承BaseVMFragment
- 不使用MVVM的继承BaseFragment
4. RecycleView
- Adapter可以继承RecycleAdapter来使用,并在类上添加注解Adapter,RecycleAdapter使用了ViewBanding,只需要实现以下一个方法
使用示例
@Adapter
class UserAdapter(iPageControl: IPageControl) :
RecyclerAdapter<User, ItemUserBinding>(iPageControl) {
override fun bindViewHolder(holder: CommonViewHolder<ItemUserBinding>, m: User, position: Int) {
holder.viewBanding {
name.text = m.name
}
}
}
5. 网络请求
- 只需要是接口类上加上注解ServiceApi,并使用NetManager.getService()获取对应的接口类
使用示例
@ServiceApi(baseUrl = "https://www.wanandroid.com/", factory = WanAndroidConverterFactory::class,interceptors = [HttpLoggingInterceptor::class])
interface WanAndroidService {
@GET("banner/json")
suspend fun banner(): List<Banner>
}
object WanAndroidRepository : WanAndroidProxy {
private val wanAndroidService = NetManager.getService(WanAndroidService::class.java)
override suspend fun queryBanner(): Banner {
val banners = wanAndroidService.queryBanner()
return banners[0]
}
}
6. 注解使用
Title-标题
6.1属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
value | StringRes | 是 | 无 | 标题内容 |
backgroundColor | ColorRes | 否 | 全局标题背景色 | 标题背景色 |
textColor | ColorRes | 否 | 全局标题文字颜色 | 标题文字颜色 |
backIcon | DrawableRes | 否 | 全局标题返回按钮图标 | 标题返回按钮图标 |
OnClickFirstDrawable-标题上第一个图标按钮的点击事件
6.2属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
value | StringRes | 是 | 无 | 按钮图片内容 |
OnClickFirstText-标题上第一个文字按钮的点击事件
6.3属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
value | StringRes | 是 | 无 | 按钮文字内容 |
OnClickSecondDrawable-标题上第二个图标按钮的点击事件
6.4属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
value | StringRes | 是 | 无 | 按钮图片内容 |
OnClickSecondText-标题上第二个文字按钮的点击事件
6.5属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
value | StringRes | 是 | 无 | 按钮文字内容 |
StatusBar-状态栏
6.6属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
hide | boolean | 否 | false | 隐藏状态栏 |
enabled | boolean | 否 | false | 状态栏是否可用 |
transparent | boolean | 否 | false | 状态栏透明 |
Prefs-SharedPreferences注解生成器
6.7属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
value | String | 否 | "" | 别名 |
mode | PrefsMode | 否 | PrefsMode.MODE_PRIVATE | 模式,对应PreferencesMode |
PrefsField-SharedPreferences字段注解
6.8属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
value | String | 否 | "" | 字段别名,如果为空则取修饰字段的参数名称 |
ObserverError-Activity和Fragment中的Flow的onError方法统一处理
6.9Adapter-RecyclerAdapter的继承类注解,加上此注解之后可以自动找到对应的layout资源
6.10GlobalConfig-全局参数配置
6.11ServiceApi-网络请求接口注解类
6.12属性 | 类型 | 必须 | 默认 | 说明 |
---|---|---|---|---|
baseUrl | String | 是 | 无 | retrofit的baseurl |
factory | Factory | 否 | GsonConverterFactory | 数据转换器 |
connectTimeout | Long | 否 | 5000 | http的超时时间 |
readTimeout | Long | 否 | 5000 | http读取超时时间 |
interceptors | Interceptor | 否 | Interceptor | http拦截器 |
7. 刷新分页
使用RefreshLayoutWrapper+RecyclerAdapter控件实现刷新功能
-
RefreshLayoutWrapper继承于SmartRefreshLayout,具体使用请看SmartRefreshLayout官方文档,默认每页数据量为16,如果想修改每页数据量,可使用如下方法更改:
RefreshLayoutWrapper.pageSize = 16
-
RefreshLayoutWrapper实现了IPageControl ,可以通过调用接口内的方法类获取刷新控件的状态和更改状态
//获取刷新的状态 iPageControl.getRefreshStatus()
-
RecyclerAdapter在实例化的时候传入IPageControl, 获取数据成功之后,只需要调用autoUpdateList(list)方法, 可以自动RefreshLayoutWrapper页码和刷新状态变化
-
数据更新失败可以调用RecyclerAdapter.updateFailed()
-
获取每页的数据量和下一页的页码,可以调用一下方法
//每页的数据量 RecyclerAdapter.pageSize = 16 //下一页的页码 RecyclerAdapter.nextPageIndex = 1
DownloadManager))
8. 文件下载器(- 单文件下载方法download(DownloadCallback)
DownloadManager.download(downloadUrl, { }, { readLength, countLength -> progressLiveData.value = (readLength * 100 / countLength).toInt() })
-
DownloadCallback
interface DownloadCallback { /** * 开始下载 */ fun onStart() /** * 下载成功 * @param path 本地保存的地址 */ fun onSuccess(path:String) /** * 下载完成 */ fun onComplete() /** * 下载进度 * @param readLength 读取的进度 * @param countLength 总进度 */ fun onProgress(readLength:Long,countLength:Long) /** * 下载错误 * @param t 错误信息 */ fun onError(t:Throwable) }
-
- 多文件下载方法multiDownload(MultiDownloadCallback)
DownloadManager.multiDownload(downloadUrls, { })
- MultiDownloadCallback
interface MultiDownloadCallback { /** * 开始下载 */ fun onStart() /** * 下载成功 * @param paths 本地保存的地址集 */ fun onSuccess(paths:MutableList<String>) /** * 下载完成 */ fun onComplete() /** * 下载错误 * @param t 错误信息 */ fun onError(t:Throwable) }
- MultiDownloadCallback