栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Kotlin+Flow+Retrofit+OKHttp+KAPT+ViewBanding+ViewModel的MVVM框架,支持协程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Kotlin+Flow+Retrofit+OKHttp+KAPT+ViewBanding+ViewModel的MVVM框架,支持协程

Gitee 地址:kmvvm
Github 地址:kmvvm
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、FlowError、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 注解处理工具
apply plugin: 'kotlinx-serialization' //序列化
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 {
    
    @DimenRes
    fun getTitleHeight(): Int

    
    @DrawableRes
    fun getTitleBackIcon(): Int

    
    @ColorRes
    fun getTitleBackground(): Int

    
    @ColorRes
    fun getTitleTextColor(): Int

    
    fun isShowTitleLine(): Boolean

    
    @ColorRes
    fun getTitleLineColor(): Int

    
    @ColorRes
    fun getLoadingColor(): Int

    
    @ColorRes
    fun getLoadingBackground(): Int

    
    fun getRecyclerEmptyBanding(parent: ViewGroup): ViewBinding

    
    fun getPageSize(): Int

    
    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其他注解参数,请看下方注解详情

//设置标题的文字
@Title(R.string.child_title)
class ChildActivity : BaseVMActivity() 

如果标题栏文字要根据接口显示不同的文字,也有接口设置

class ChildActivity : BaseVMActivity() {
    @OnClickFirstDrawable(R.drawable.more)
    fun clickFirstDrawable(v: View) {
        updateTitle("更改标题")
    }
}
2.2 状态栏注解使用

使用示例

StatusBar其他注解参数,请看下方注解详情

//弃用注解
@StatusBar(hide = true)
class FullScreenActivity : BaseActivity()
2.3 标题右侧文字或图标按钮注解使用

使用示例

注解修饰的方法只能可以带View参数,也可以不带View参数,看自身的需求

@Title(R.string.child_title)
class ChildActivity : BaseVMActivity() {
    @OnClickFirstDrawable(R.drawable.more)
    fun clickFirstDrawable(v: View) {
        SnackbarManager.show(bodyBinding.root, "第一个图标按钮点击生效")
        updateTitle("nihao")
    }

    @OnClickFirstText(R.string.more)
    fun clickFirstText() {
        SnackbarManager.show(bodyBinding.root, "第一个文字按钮点击生效")
        updateTitle("12354")
    }

    @OnClickSecondDrawable(R.drawable.more)
    fun clickSecondDrawable(v: View) {
        SnackbarManager.show(bodyBinding.root, "第二个图标按钮点击生效")
        updateTitle("nihao")
    }

    @OnClickSecondText(R.string.more)
    fun clickSecondText() {
        SnackbarManager.show(bodyBinding.root, "第二个文字按钮点击生效")
        updateTitle("12354")
    }
}
2.4 提示框
  • Android 11 之后,Toast已经不支持自定义Toast,原生的Toast是很难看的
  • 本框架使用SnackBar做提示框

使用示例

@OnClickSecondDrawable(R.drawable.more)
fun clickSecondDrawable(v: View) {
    snackBar("第二个图标按钮点击生效")
}
3. Fragment
  • 使用MVVM的继承BaseVMFragment
  • 不使用MVVM的继承BaseFragment
3.1 提示框
  • Android 11 之后,Toast已经不支持自定义Toast,原生的Toast是很难看的
  • 本框架使用SnackBar做提示框

使用示例

snackbar.setOnClickListener {
    snackBar("提示框")
}
4. RecycleView

Adapter可以继承RecycleAdapter来使用,并在类上添加注解Adapter
,RecycleAdapter使用了ViewBanding,只需要实现以下一个方法

使用示例

@Adapter
class UserAdapter(iPageControl: IPageControl) :
    RecyclerAdapter(iPageControl) {

    override fun bindViewHolder(holder: CommonViewHolder, m: User, position: Int) {
        holder.viewBanding {
            name.text = m.name
        }
    }
}
5.刷新分页控件(RefreshRecyclerView)
  • RefreshRecyclerView集成了RefreshLayoutWrapper+RecyclerView

不用关心分页的逻辑,分页的刷新逻辑实现都在RefreshLayoutWrapper

  • 只需要设置LayoutManager和RecyclerAdapter,提供了setLayoutManager和setAdapter方法
  • 在获取到数据的时候调用updateData方法
  • 获取数据失败的时候调用updateError方法
  • 如果使用了lifecycleFlowRefresh方法,updateData方法和updateError方法都不用关心
  • 提供自定义属性recycler_background(设置RecyclerView的背景色)

    

使用示例



    

    

    

bodyBinding.refresh.run {
    setOnRefreshLoadMoreListener { nextPageIndex ->
        lifecycleFlowRefresh(viewModel.queryArticles(nextPageIndex), this)
    }
}
6. 网络请求 6.1只需要是接口类上加上注解ServiceApi,并使用NetManager.getService()获取对应的接口类

使用示例

@ServiceApi(
    baseUrl = "https://www.wanandroid.com/",
    responseConverter = ResponseBodyConverter::class,
    interceptors = [RequestInterceptor::class],
    debugInterceptors = [OkHttpProfilerInterceptor::class]
)
interface WanAndroidService {
    @GET("banner/json")
    suspend fun banner(): List
}
object WanAndroidRepository {
    private val wanAndroidService = NetManager.getService(WanAndroidService::class.java)
    fun getBanners(): Flow> {
        //这里如果用flowOf的话,方法上面必须加上suspend关键字
        return flow {
            emit(wanAndroidService.queryBanner())
        }
    }
}
class IndexViewModel : BaseViewModel() {
    fun queryBanners(): Flow> {
        return WanAndroidRepository.getBanners()
    }
}
//Activity或者Fragment
lifecycleFlowLoadingView(viewModel.queryBanners()) {
    val images = mutableListOf()
    this.forEach {
        images.add(it.imagePath)
    }
    bodyBinding.banner.run {
        setImages(images)
        start()
    }
}
6.2 Response转换器 6.2.1
  • 一般Response发返回结果会是如下
{
	code:"SUCCESS",
	errorMsg:"成功",
	data:...
}
  • 在code返回SUCEESSD的时候, 我们在Retrofit的Api接口里面只想拿到data的数据做返回,我们想在Converter里面处理掉code返回错误码的逻辑,就可以继承BaseResponseBodyConverter,内部已经实现了将response转化为data的逻辑

代码示例

class ResponseBodyConverter :
    BaseResponseBodyConverter() {
    override fun getResultClass(): KClass> {
        return Result::class
    }

    override fun handlerErrorCode(errorCode: String, msg: String): Exception {
        return NullPointerException()
    }
}
  • 再将实现了BaseResponseBodyConverter的类加到ServiceApi注解的responseConverter属性上
6.2.2
  • 如果想直接拿response的结果作为网络请求的返回值,可以直接将SerializationResponseBodyConverter加到ServiceApi注解的responseConverter属性上
6.3 Activity和Fragment封装了网络请求方法(带lifecycleScope)
  • lifecycleFlowRefresh(flow: Flow,refresh: RefreshRecyclerView)
    -刷新+RecycleView的网络请求封装
  • lifecycleFlow(flow: Flow, callback: T.() -> Unit)-不带loading的网络请求封装
  • lifecycleFlowLoadingView(flow: Flow, callback: T.() -> Unit)-带loadingView的网络请求封装
  • lifecycleFlowLoadingDialog(flow: Flow, callback: T.() -> Unit)-带loadingDialog的网络请求封装
7. 注解使用 7.1 Title-标题
属性类型必须默认说明
valueStringRes标题内容
backgroundColorColorRes全局标题背景色标题背景色
textColorColorRes全局标题文字颜色标题文字颜色
backIconDrawableRes全局标题返回按钮图标标题返回按钮图标
7.2 OnClickFirstDrawable-标题上第一个图标按钮的点击事件
属性类型必须默认说明
valueDrawableRes按钮图片资源
7.3 OnClickFirstText-标题上第一个文字按钮的点击事件
属性类型必须默认说明
valueStringRes按钮文字内容
7.4 OnClickSecondDrawable-标题上第二个图标按钮的点击事件
属性类型必须默认说明
valueDrawableRes按钮图片资源
7.5 OnClickSecondText-标题上第二个文字按钮的点击事件
属性类型必须默认说明
valueStringRes按钮文字内容
7.6 StatusBar-状态栏
属性类型必须默认说明
hidebooleanfalse隐藏状态栏
enabledbooleanfalse状态栏是否可用
transparentbooleanfalse状态栏透明
7.7 Prefs-SharedPreferences注解生成器
属性类型必须默认说明
valueString“”别名
modePrefsModePrefsMode.MODE_PRIVATE模式,对应PreferencesMode
7.8 PrefsField-SharedPreferences字段注解
属性类型必须默认说明
valueString“”字段别名,如果为空则取修饰字段的参数名称
7.9 FlowError-Activity和Fragment中的Flow的onError方法统一处理 7.10 Adapter-RecyclerAdapter的继承类注解,加上此注解之后可以自动找到对应的layout资源 7.11 GlobalConfig-全局参数配置
  • 注解在IGlobalConfig接口的实现类上面
7.12 ServiceApi-网络请求接口注解类
属性类型必须默认说明
baseUrlStringretrofit的baseurl
responseConverterConverter接收数据转换器
connectTimeoutLong5000http的超时时间
readTimeoutLong5000http读取超时时间
interceptorsInterceptorInterceptorhttp拦截器
debugInterceptorsInterceptorInterceptordebug模式下的http拦截器,只有NetManager.setDebug(true),才会生效
8. 文件下载器(DownloadManager)-支持协程方式和RxJava两种方式的下载(RxJavaDownloadManager、CoroutinesDownloadManager)
  • 设置下载路径

    DownloadManager.setDownloadPath("${ContextManager.context.externalCacheDir!!.absolutePath}/kmvvmDownload")
    
  • 单文件下载方法download(DownloadCallback)

RxJavaDownloadManager.download(downloadUrl, {
        //下载完成回调
    }, { downloadProgress ->
        //下载进度回调
    })
  • DownloadCallback
interface DownloadCallback {
        
        fun onStart()
    
        
        fun onSuccess(path:String)
    
        
        fun onComplete()
    
		
        fun onProgress(downloadProgress: DownloadProgress)
    
        
        fun onError(t:Throwable)
    }
  • 多文件下载方法multiDownload(MultiDownloadCallback)
DownloadManager.multiDownload(downloadUrls, {
         //下载完成回调
    }, { downloadProgress ->
        //下载进度回调
    })
  • MultiDownloadCallback
interface MultiDownloadCallback {
    
    fun onStart()
      
    
    fun onSuccess(paths:MutableList)
    
    
    fun onProgress(downloadProgress: DownloadProgress)
  
    
    fun onComplete()
      
    
    fun onError(t:Throwable)
}
9. 工具库

utils

混淆
-keep class com.catchpig.annotation.enums.**

-keep class com.google.android.material.snackbar.Snackbar {*;}

-keep @com.catchpig.annotation.Adapter class * {*;}
-keep @com.catchpig.annotation.ServiceApi class * {*;}

-keep public class **.databinding.*Binding {*;}

-keep class **.*_Compiler {*;}

-keep class com.gyf.immersionbar.* {*;}
-dontwarn com.gyf.immersionbar.**

#序列化混淆
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
    static <1>$Companion Companion;
}

# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
    static **$* *;
}
-keepclassmembers class <1>$<3> {
    kotlinx.serialization.KSerializer serializer(...);
}

# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}

# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
第三方库 SmartRefreshLayout-刷新控件 Immersionbar-状态栏 RxJava3 RxAndroid OkHttp Retrofit Gson kotlinpoet - kt代码生成工具 AndroidUtilKTX - 工具类 LoadingView - Loading动画 coroutines - 协程 serialization-序列化 其他 欢迎大家在issue上提出问题,我这边会不定时的看issue,解决问题
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/827262.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号