# kotlin-mvp
**Repository Path**: catchpig/kotlin-mvp
## Basic Information
- **Project Name**: kotlin-mvp
- **Description**: kotlin的mvp框架(koin+Rxjava+Retrofit+OkHttp):使用了aop,apt思想和mvp模式
- **Primary Language**: Kotlin
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2021-09-11
- **Last Updated**: 2022-06-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# [kotlin-mvp](https://github.com/catch-pig/kotlin-mvp)
[](https://jitpack.io/#catch-pig/kotlin-mvp)
## 技术要点
### 1. RxJava+Retrofit+OkHttp实现链式http请求
### 2. 封装基类:BaseActivity、BasePresenterActivity、BaseFragment、BasePresenterFragment、RecycleAdapter、BasePresenter
### 3. 封装工具扩展类:CalendarExt、ContextExt、DateExt、EditTextExt、GsonExt、RxJavaExt、StringExt
### 4. 引入LifeCycle,将Presenter和Activity的生命周期绑定在一起
### 5. 将在Application中初始化移至到ContentProvider中,从而不用封装BaseApplication
### 6. AOP(面向切面)封装注解:TimeLog、ClickGap、MethodLog
### 7. APT(编译时注解)封装注解:OnClickFirstDrawable、OnClickFirstText、OnClickSecondDrawable、OnClickSecondText、Prefs、PrefsField、StatusBar
### 8. Koin对类的生命周期做一个管理
## 最低兼容:21
## Gradle
### 1. 在Project的build.gradle中添加
```
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
```
### 2. [AspectJX](https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx)的使用请参考官方文档
```
dependencies {
classpath 'com.github.franticn:gradle_plugin_android_aspectjx:2.0.10'
}
```
### 3. 在app的build.gradle的添加
```
apply plugin: 'kotlin-kapt' // 使用 kapt 注解处理工具
apply plugin: 'android-aspectjx'
aspectjx {
exclude 'versions.9.module-info.class'
exclude 'module-info.class'
}
```
### 4. 添加依赖
```
implementation "com.github.catch-pig.kotlin-mvp:mvp:last_version"
kapt "com.github.catch-pig.kotlin-mvp:compiler:last_version"
```
## 使用
### 1. 在需要使用状态栏、标题栏、加载动画的主题中配置全局参数:
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|title_bar_back_icon|DrawableRes|是|无|标题栏的返回图标|
|title_bar_background|ColorRes|是|无|标题栏的背景色|
|title_bar_text_color|ColorRes|是|无|标题栏的文字颜色|
|title_bar_show_line|boolean|否|false|标题栏的下方的线条是否显示|
|loading_view_color|ColorRes|是|无|loading动画颜色|
|loading_view_background|ColorRes|是|无|loading动画背景色|
|recycle_view_empty_layout|LayoutRes|否|[emptyLayout](./mvp/src/main/res/layout/view_load_empty.xml)|列表空页面|
> 使用示例:
```
```
### 2. Activity
* 使用MVP的继承BasePresenterActivity
* 不使用MVP的继承BaseActivity
### 3. Fragment
* 使用MVP的继承BasePresenterFragment
* 不使用MVP的继承BaseFragment
### 4. 如果使用RecycleView的时候,Adapter可以继承RecycleAdapter来使用
> 在app的build.gradle的android下添加如下代码:
```
//启用实验性功能
androidExtensions {
experimental = true
}
```
> 只需要实现以下两个方法
```
class UserAdapter(iPageControl: IPageControl):RecyclerAdapter(iPageControl) {
override fun layoutId(): Int {
return R.layout.item_user
}
override fun bindViewHolder(holder: CommonViewHolder, m: User, position: Int) {
//使用的experimental之后,可以直接holder.控件ID,不需要holder.itemView.控件ID
holder.name.text = m.name
}
}
```
### 5. 注解使用
#### 5.1 [Title](./annotation/src/main/java/com/catchpig/annotation/Title.kt)-标题
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|StringRes|是|无|标题内容|
|backgroundColor|ColorRes|否|全局标题背景色|标题背景色|
|textColor|ColorRes|否|全局标题文字颜色|标题文字颜色|
|backIcon|DrawableRes|否|全局标题返回按钮图标|标题返回按钮图标|
#### 5.2 [OnClickFirstDrawable](./annotation/src/main/java/com/catchpig/annotation/OnClickFirstDrawable.kt)-标题上第一个图标按钮的点击事件
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|StringRes|是|无|按钮图片内容|
#### 5.3 [OnClickFirstText](./annotation/src/main/java/com/catchpig/annotation/OnClickFirstText.kt)-标题上第一个文字按钮的点击事件
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|StringRes|是|无|按钮文字内容|
#### 5.4 [OnClickSecondDrawable](./annotation/src/main/java/java/com/catchpig/annotation/OnClickSecondDrawable.kt)-标题上第二个图标按钮的点击事件
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|StringRes|是|无|按钮图片内容|
#### 5.5 [OnClickSecondText](./annotation/src/main/java/com/catchpig/annotation/OnClickSecondText.kt)-标题上第二个文字按钮的点击事件
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|StringRes|是|无|按钮文字内容|
#### 5.6 [StatusBar](./annotation/src/main/java/com/catchpig/annotation/StatusBar.kt)-状态栏
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|hide|boolean|否|false|隐藏状态栏|
|enabled|boolean|否|false|状态栏是否可用|
|transparent|boolean|否|false|状态栏透明|
#### 5.7 [TimeLog](./annotation/src/main/java/com/catchpig/annotation/TimeLog.kt)-打印方法和构造方法执行的时间
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|[LEVEL](./annotation/src/main/java/com/catchpig/annotation/TimeLog.kt)|否|[LEVEL.D](./annotation/src/main/java/com/catchpig/annotation/TimeLog.kt)|日志等级|
#### 5.8 [ClickGap](./annotation/src/main/java/com/catchpig/annotation/ClickGap.kt)-重复点击延时
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|Long|否|800毫秒|重复点击间隔|
#### 5.9 [Prefs](./annotation/src/main/java/com/catchpig/annotation/Prefs.kt)-SharedPreferences注解生成器
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|String|否|""|别名|
|mode|[PrefsMode](./annotation/src/main/java/com/catchpig/annotation/enums/PrefsMode.kt)|否|PrefsMode.MODE_PRIVATE|模式,对应PreferencesMode|
#### 5.10 [PrefsField](./annotation/src/main/java/com/catchpig/annotation/PrefsField.kt)-SharedPreferences字段注解
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|String|否|""|字段别名,如果为空则取修饰字段的参数名称|
#### 5.11 [MethodLog](./annotation/src/main/java/com/catchpig/annotation/MethodLog.kt)-打印方法和构造方法以及参数的值
|属性|类型|必须|默认|说明|
|---|:---:|:---|:---|:---|
|value|[LEVEL](./annotation/src/main/java/com/catchpig/annotation/MethodLog.kt)|否|[LEVEL.D](./annotation/src/main/java/com/catchpig/annotation/MethodLog.kt)|日志等级|
### 6. 刷新分页
#### 使用RefreshLayoutWrapper+RecyclerAdapter控件实现刷新功能
+ ***RefreshLayoutWrapper继承于[SmartRefreshLayout](https://github.com/scwang90/SmartRefreshLayout),具体使用请看SmartRefreshLayout官方文档,默认每页数据量为16,如果想修改每页数据量,可使用如下方法更改:***
```
RefreshLayoutWrapper.pageSize = 16
```
+ ***RefreshLayoutWrapper实现了[IPageControl](./mvp/src/main/java/com/catchpig/mvp/widget/refresh/IPageControl.kt),可以通过调用接口内的方法类获取刷新控件的状态和更改状态***
```
//获取刷新的状态
iPageControl.getRefreshStatus()
```
+ ***RecyclerAdapter在实例化的时候传入IPageControl,
获取数据成功之后,只需要调用autoUpdateList(list)方法,
可以自动RefreshLayoutWrapper页码和刷新状态变化***
+ ***数据更新失败可以调用RecyclerAdapter.updateFailed()***
+ ***获取每页的数据量和下一页的页码,可以调用一下方法***
```
//每页的数据量
RecyclerAdapter.pageSize = 16
//下一页的页码
RecyclerAdapter.nextPageIndex = 1
```
### 7. 文件下载器([DownloadManager](./mvp/src/main/java/com/catchpig/mvp/manager/DownloadManager.kt)))
+ 在application的onCreate中startKoin,加入[downloadModule](./mvp/src/main/java/com/catchpig/mvp/di/AppModule.kt)
```
startKoin {
modules(downloadModule)
}
```
* downloadModule
```
/**
* 下载相关类的初始化管理
*/
const val NAMED_DOWNLOAD = "download"
val downloadModule = module {
single(named(NAMED_DOWNLOAD)) { (downloadProgressListener: DownloadProgressListener)->
DownloadInterceptor(downloadProgressListener)
} bind Interceptor::class
single(named(NAMED_DOWNLOAD)) { (downloadProgressListener: DownloadProgressListener, timeout:Long)->
OkHttpClient
.Builder()
.connectTimeout(timeout, TimeUnit.SECONDS)
.addInterceptor(get())
.addInterceptor(get(named(NAMED_DOWNLOAD)){ parametersOf(downloadProgressListener)})
.build()
}
single(named(NAMED_DOWNLOAD)) { (baseUrl:String,timeout:Long,downloadProgressListener: DownloadProgressListener)->
Retrofit
.Builder()
.baseUrl(baseUrl)
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.client(get(named(NAMED_DOWNLOAD)){ parametersOf(downloadProgressListener,timeout)})
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(DownloadService::class.java)
}
single {
DownloadManager()
}
}
```
+ 调用下载方法download([DownloadInfo](./mvp/src/main/java/com/catchpig/mvp/bean/DownloadInfo.kt),[DownloadCallback](./mvp/src/main/java/com/catchpig/mvp/listener/DownloadCallback.kt))
```
val downloadInfo = DownloadInfo("https://wanandroid.com/","blogimgs/2d120094-e1ee-47fb-a155-6eb4ca49d01f.apk")
model.download(downloadInfo,object : DownloadCallback {
override fun onStart() {
}
override fun onSuccess(path: String) {
view.activity().installApk(path)
}
override fun onComplete() {
}
override fun onProgress(readLength: Long, countLength: Long) {
view.setDownloadProgress((readLength*100/countLength).toInt())
}
override fun onError(t: Throwable) {
println(t.message)
}
})
```
* DownloadInfo
```
data class DownloadInfo(
/**
* 域名
*/
val baseUrl:String,
/**
* 下载地址
*/
val url:String,
/**
* 连接超时时间(单位:秒)
*/
val connectTimeout:Long = 5
){
override fun toString(): String {
return "$baseUrl$url"
}
}
```
* 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)
}
```
## 第三方库
### [SmartRefreshLayout](https://github.com/scwang90/SmartRefreshLayout)-刷新控件
### [Immersionbar](https://github.com/gyf-dev/ImmersionBar)-状态栏
### [Koin](https://github.com/InsertKoinIO/koin)
### [RxJava3](https://github.com/ReactiveX/RxJava)
### [RxAndroid](https://github.com/ReactiveX/RxAndroid)
### [OkHttp](https://github.com/square/okhttp)
### [Retrofit](https://github.com/square/retrofit)
### [Gson](https://github.com/google/gson)
### [AndroidUtilKTX](https://github.com/lulululbj/AndroidUtilCodeKTX)-工具类
### [LoadingView](https://github.com/catch-pig/LoadingView)-Loading动画