2 Star 0 Fork 0

Kotle / MvvmModule

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md.old 19.73 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
前言
==
```
本文全属于个人理解
mvvm 数据层和视图层双向绑定,一层改变,另一层也会自动改变,数据驱动ui,当然也不是只有安卓有mvvm,在安卓的mvvm出现之前,已经有mvvm的模式了。
(对于Android来说,结合dataBinding的使用才能发挥出mvvm的效果,好处很多,弊端就是不便于调试)
自己抽取mvp和mvvm的一些优点,结合google官方的一些demo整理的一个框架
```
项目介绍
==
* 项目地址([码云](https://gitee.com/kotle/MvvmLib))
* 功能介绍
```
1.基础的mvvm框架功能
[1] 创建ViewModel只需要一个泛型
[2] ViewModel支持一个或者多个Model
[3] activity,viewModel,Model,fragment,dialog均封装了常用方法
[4] Dilaog和PopupWindow加入动画效果,使用也更简单
[5] 简单的MessageBus(仿EventBus),实现简单的消息传递
[6] activity,fragment,dialog,实现同一个接口,方便以后互转
[7] LiveBean<T>(对LiveData封装),方便viewModel和Activity通讯
[8] 封装RecycleView的Adapter(支持单个viewType或者多个viewType,加载更多的监听,数据刷新等等)
[9] LoadingViewSwitcher和LoadingSwipeRefreshLayout(带有动画的切换空布局,错误布局,主布局)
...
2.大量常用工具封装
[1] ActivityUtils.kt(actiivty跳转的封装)
[2] Net.kt (对okHttp封装,发送get,post请求)
[3] NetWorkUtils.obj (对网络状况的监听)
[4] OtherUtils.kt (不好归类的工具,请看详细介绍)
[5] RetrofitHelper.obj (对Retrofit封装)
[6] ScreenAdaptation.obj (屏幕适配,今日头发方案)
[7] SpUtils.kt (SharedPreferences,存取数据更方便)
[8] ThreadUtil.obj (线程池,使用子线程更方便,不建议再使用new Thread()开启线程)
[9] ViewExtFun.kt (view的一些扩展方法,比如设置网络图片到ImagerView)
...
```
MVVM详细介绍
====
强烈建议使用的时候,再做一层封装,比如使用**BaseActivity**继承**MvvmActivty**,然后你的所有**Activity**继承**BaseActivity**。
使用介绍
**MvvmActivity**
=====
所有activity的基类,你的activity继承这个类。
默认必须实现以下方法
```kotlin
abstract class YourBaseActivity<T : MvvmViewModel<*>> : MvvmActivity<T>() {
/**
* 获取contentView
* 返回layoutRes或者view对象
*/
override fun getLayoutResOrView(): Any? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
/**
* 获取需要注册点击事件的按钮
*/
override fun getClickView(): List<View?>? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
/**
* 点击按钮的回调,默认做了防止快速点击的处理
*/
override fun onSingleClick(view: View) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
/**
* 注册你的viewModel里的liveData
*/
override fun initViewModel() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
/**
* 初始化界面
*/
override fun initUi(savedInstanceState: Bundle?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
/**
* 初始化数据,在initUi(savedInstanceState: Bundle?)之后调用
*/
override fun initData() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
```
继承**MvvmActiivty**其他可选的实现方法
```kotlin
/*************************************************可选的实现方法***************************************/
/**
* MvvmViewModel调用postError()或者sendError()之后
* MvvmModel调用postError()或者sendError()之后
* 这里会收到回调
*/
override fun onErrorByLiveData(errorMsg: String?, errorCode: Int) {
super.onErrorByLiveData(errorMsg, errorCode)
}
/**
* 按钮点击回调
*/
override fun onClick(v: View?) {
super.onClick(v)
}
/**
* 两次按钮点击的间隔,多少时间内,只相应一次回调
*/
override fun getDoubleClickSpace(): Long {
return super.getDoubleClickSpace()
}
/**
* 同过MessageBus发送的数据,会在这里收到回调
* MessageBus怎么使用,请看后面介绍
*/
override fun onMessageBus(event: Any?, code: Int) {
super.onMessageBus(event, code)
}
```
继承了**MvvmActivity**的子类,支持调用的方法
```kotlin
//获取通过泛型注册的ViewModel
val mViewModel
//动态申请权限
getPermission(permission: MutableList<String>, needPermissionCall: Function1<Boolean, Unit>)
//注册LiveData,忽略LiveData的value为null的情况
inline fun <T> LiveBean<T>.register(crossinline observer: (LiveBean<T>) -> Unit)
```
**MvvmFragment**
=====
使用参照MvvmActivity
**MvvmDialog**
=====
使用参照MvvmFragment,
对话框为了高内聚,不强制绑定一个ViewModel(即传入ViewModel泛型)
继承了**MvvmDialog**的子类,支持实现的方法
```kotlin
fun show(activity: FragmentActivity?) {
tryError {
activity?.let {
show(it.supportFragmentManager, javaClass.simpleName)
}
}
}
/**
* 设置对话框背景透明度
* 0-1
*/
protected open fun getDialogDimAmount(): Float {
return 0.6f
}
/**
* 触摸外面是否可以取消
*/
protected open fun isCanceledOnTouchOutside() = false
/**
* 设置布局参数
*/
protected open fun onRootViewLayoutParams(lp: FrameLayout.LayoutParams) {
lp.gravity = Gravity.CENTER
}
/**
* 设置对话框进入退出动画
*/
@StyleRes
protected open fun getDialogAnim(): Int? {
return null
}
/**
* 是否需要默认,进入退出动画
*/
protected open fun isNeedDefaultAnim(): Boolean = true
```
**MvvmViewModel**
=====
控制层,逻辑处理
```kotlin
/**
* 不需要实现任何方法
* 继承MvvmViewModel<T>,即为一个ViewModel绑定一个Model类
*/
class YourBaseViewModel<T:MvvmModel> :MvvmViewModel<T>(){
}
/**
* 不需要实现任何方法
* 继承MvvmViewModelNoGeneric,即为一个ViewModel绑定一个多个Model类
* 使用getModel<T>(),来获取继承了MvvmModel的对象
*/
class YourBaseViewModel1:MvvmViewModelNoGeneric(){
}
```
继承了**MvvmViewModel**的子类,支持调用的方法
```kotlin
//继承了MvvmViewModel<T>的子类,获取model。
//继承MvvmViewModelNoGeneric不能使用
val mModel
/**
* activity有个地方直接接受错误的回调
* 方便统一处理
*/
fun sendError(errorMsg: String?, errorCode: Int = -2) {
viewModelErrorLiveData.value = MvvmModel.ErrorDataBean(errorMsg, errorCode)
}
/**
* activity有个地方直接接受错误的回调
* 方便统一处理
* 在子线程调用
*/
fun postError(errorMsg: String?, errorCode: Int = -2) {
viewModelErrorLiveData.postValue(MvvmModel.ErrorDataBean(errorMsg, errorCode))
}
/**
* 销毁的时候结束请求
*/
fun Call.cancelOnDestroy(): Call {
callList.add(this)
return this
}
/**
* 异步执行
* 销毁的时候结束请求
*/
fun Call.async(callback: Callback) {
callList.add(this)
enqueue(callback)
}
/**
* 同步执行
* 销毁的时候结束请求
*/
fun Call.await(): Response {
callList.add(this)
return execute()
}
```
**MvvmModel**
=====
做一些获取数据的操作,从网络或者数据库
```kotlin
/**
* 不需要实现任何方法
* 继承MvvmModel
*/
class YourBaseModel :MvvmMode(){
}
```
继承了**MvvmModel**的子类,支持调用的方法
```kotlin
/**
* activity有个地方直接接受错误的回调
* 方便统一处理
*/
fun sendError(errorMsg: String?, errorCode: Int = -2) {
viewModelErrorLiveData.value = MvvmModel.ErrorDataBean(errorMsg, errorCode)
}
/**
* activity有个地方直接接受错误的回调
* 方便统一处理
* 在子线程调用
*/
fun postError(errorMsg: String?, errorCode: Int = -2) {
viewModelErrorLiveData.postValue(MvvmModel.ErrorDataBean(errorMsg, errorCode))
}
/**
* 销毁的时候结束请求
*/
fun Call.cancelOnDestroy(): Call {
callList.add(this)
return this
}
/**
* 异步执行
* 销毁的时候结束请求
*/
fun Call.async(callback: Callback) {
callList.add(this)
enqueue(callback)
}
/**
* 同步执行
* 销毁的时候结束请求
*/
fun Call.await(): Response {
callList.add(this)
return execute()
}
```
扩展
=====
使用封装的LiveBean<T>向Activity传递数据(也可以不使用,不强制)
在ViewModel类中创建LiveBean
```kotlin
class YourBaseViewModel1 : MvvmViewModelNoGeneric() {
val testLiveBean = createLiveBean<String>()
init {
testLiveBean.start()
testLiveBean.success("测试数据")
testLiveBean.fail("发生了错误")
}
}
```
在Activity/Fragment类中创建注册监听
```kotlin
override fun initViewModel() {
mViewModel.testLiveBean.register {
when (it.status) {
LiveBeanStatus.START -> TODO()
LiveBeanStatus.SUCCESS -> TODO()
LiveBeanStatus.FAIL -> TODO()
}
}
}
```
所有工具类详细介绍
====
* **recyclerView适配器**
BaseRcvAdapter 单个item适配器
BaseMutableRcvAdapter 多个item适配器
自己的适配器选择继承上面两个类
```kotlin
//设置item的点击事件,默认处理了防止多次点击
fun setOnItemClickListener(id: Int? = null, listener: ((itemView: View, position: Int, itemData: P) -> Unit))
//带有动画效果的刷新列表
fun refreshList(newList: MutableList<P>, areContentsTheSame: ((old: P?, new: P?) -> Boolean) = { _, _ -> false })
//加载数据
fun loadMoreList(newList: MutableList<P>)
//是否支持滑到底部的监听(对于分页,自动加载数据很好用),只能子类实现这个方法,不能外部调用
open fun isAutoLoadMore() = false
// 获取自定义的加载更多布局,只能子类实现这个方法,不能外部调用
open fun getAutoLoadMoreLayoutRes(): Int = R.layout.default_load_more
// 设置滑到底部的监听
fun setOnScrollEndListener(l: Function1<MutableList<P>, Unit>)
//所有数据加载完毕的回调,可以做一下view的改变,有默认处理,,只能子类实现这个方法,不能外部调用
open fun onLoadMoreEnd(loadMoreView: View?)
```
* **ActivityUtils.kt**
跳转到下一个activity
```kotlin
//activity跳转,普通跳转,默认动画
infix fun Context.navigateTo(cls: Class<*>)
//activity跳转,普通跳转,默认动画,可以设置intent携带参数
inline fun Activity.navigateTo(cls: Class<*>, setParams: (Intent) -> Unit)
//携带view的动画,从一个界面飞入另一个
fun Activity.navigateWithViews(cls: Class<*>, vararg viewName: Pair<View, String>)
//携带view的动画,从一个界面飞入另一个,可以设置intent携带参数
inline fun Activity.navigateWithViews(cls: Class<*>, vararg viewName: Pair<View, String>, setParams: (Intent) -> Unit)
// activity跳转,普通跳转,从某个按钮展开的动画
fun Activity.navigateUpScale(view: View, cls: Class<*>)
// activity跳转,普通跳转,从某个按钮展开的动画,使用intent携带参数
inline fun Activity.navigateUpScale(view: View, cls: Class<*>, setParams: (Intent) -> Unit)
//状态栏文字颜色,只有白色和黑色
fun Activity.isStatusBarBlackTextColor(isDark: Boolean)
//回到桌面,不退出app
fun Activity.goHome()
//跳转到默认浏览器
fun Context.goToWeb(url: String)
//打电话,处理了权限请求
fun MvvmActivity<*>.goCallPhone(number: String)
//获取设备imei
fun getIMEI(context: Context): String
//结束所有app
fun Context.finishAllActivity()
```
* **Net.kt**
封装一些网络请求操作
```kotlin
//单例对象,在调用initOkHttp()之后可以直接使用
val gson = Gson()
lateinit var okHttpClient: OkHttpClient
lateinit var app: Application
//{@link com.yizisu.basemvvm.utils.MvvmConfig}应该在此方法之前设置
//初始化mvvm库,使用mvvm库这个方法必须调用
fun initOkHttp(application: Application, client: ((OkHttpClient.Builder) -> Unit)? = null)
//发起网络请求
fun <T> Request.yzsHttp(cls: Class<T>, success: (T) -> Unit, fail: (Throwable) -> Unit): Call
//发起网络请求
fun Request.yzsHttp(success: (Response) -> Unit, fail: (Throwable) -> Unit): Call
//String HttpUrl URL发起get请求
fun String.yzsHttpGet(...): Call
//post请求:参数类型RequestBody
fun String.yzsHttpPost(requestBody: RequestBody,...): Call
//post请求:参数类型表单
fun String.yzsHttpPost(formData: HashMap<String, String>,...): Call
//post请求:参数类型Json
fun String.yzsHttpPost(json: String,...): Call
//post请求:参数类型Json
fun String.yzsHttpPost(json: String,...): Call
//map集合转为表单格式的请求体
fun HashMap<String, String>.createFormBody(): RequestBody
//任意可被gson解析的对象转为Json格式请求体
fun Any.createJsonBody(): RequestBody
//日志打印,MvvmConf.IS_DEBUG为true才打印
fun Any.logV(msg: String?)
fun Any.logI(msg: String?)
fun Any.logD(msg: String?)
fun Any.logW(msg: String?)
fun Any.logE(msg: String?)
```
* **NetWorkUtils.obj**
网络是否连接,以及断开,连接监听
```kotlin
//网络是否连接
val isNetWorkConnect: Boolean
/***
* 当前链接是否wifi
* null:没有网络链接
* true:wifi
* false:有连接但不是wifi
*/
val isWifi: Boolean?
//设置网络改变的监听事件
fun setOnNetChangeListener(listener: (isConnect: (Boolean), isWifi: (Boolean?)) -> Unit)
```
* **ScreenAdaptation.obj**
屏幕适配相关
```kotlin
//设置屏幕适配,默认在MvvmActivity已开启。
fun setCustomDensity(activity: Activity, application: Application)
```
* **SpUtils.kt**
SharedPreferences相关操作类
```kotlin
//SharedPreferences文件名,本工具类操作的文件名
var SP_FILE_NAME = "defaultName"
//获取SharedPreferences
fun Context.getSp(): SharedPreferences
//数据保存再sp,只支持sp支持的基本类型
fun Context.spSet(keyName: String?, keyValue: Any?)
//通过key从Sp获取数据
fun <T> Context.spGet(keyName: String, default: T): T
//通过key移除数据
fun Context.spRemove(keyName:String)
```
* **ThreadUtil.obj**
线程池工具类
```kotlin
//单个线程执行任务,当此线程正在执行的时候,其他任务等待
fun singleThreadRun(runnable: Runnable)
//开启多个线程(手机cup的个数)执行任务
fun muchThreadThreadRun(runnable: Runnable)
```
* **ViewExtFun.kt**
view的扩展方法类
```kotlin
//从res获取颜色
fun Context.getResColor(@ColorRes colorRes: Int): Int
//从res获取图片
fun Context.getResDrawable(@DrawableRes drawableRes: Int): Drawable?
//设置文本颜色
infix fun TextView.setTextColorByRes(@ColorRes colorRes: Int)
//设置文本
infix fun TextView.textFrom(@StringRes strRes: Int)
infix fun TextView.textFrom(str: CharSequence?)
//一个textView设置多样的文本(SpanBean:文本,颜色,文本大小,文字点击事件)
infix fun TextView.textFromSpanBean(textList: MutableList<SpanBean>)
//从网络上加载图片,显示在ImageView
fun ImageView.setImageFromNet(url: String?, activity: Context)
fun ImageView.setImageFromNet(url: String?, activity: Activity)
fun ImageView.setImageFromNet(url: String?, activity: android.support.v4.app.Fragment)
//从网络上加载图片,显示在ImageView,裁剪为圆形
infix fun ImageView.setCircleImageFromNet(url: String?)
infix fun ImageView.setCircleImageFromNet(resId: Int?)
infix fun ImageView.setImageFromNet(url: String?)
fun ImageView.setImageFromNet(url: String?, width: Int, height: Int)
infix fun ImageView.clearFromFragment(fragment: Fragment)
//view隐藏
fun View.gone()
//view可见
fun View.visible()
//view不可见
fun View.invisible()
```
* **OtherUtil.kt**
其他杂七杂八的工具类
```kotlin
//捕获错误,默认不处理错误
fun tryError(handlerError: ((Throwable) -> Unit)? = null, finally: (() -> Unit)? = null, code: () -> Unit)
//dp转px(可能会有误差)
fun Context.dp2Px(dp:Float):Float
//用AsyncTask代替new Thread,减少消耗,调用start()开启任务
//虽然创建多个对象,但是他自己会用一个线程池
// 一个对象只是一个任务。还可以使用ThreadUtil里面的工具方法
class AsyncThread(private val isSerial: Boolean = false/*是否按顺序一个一个执行任务*/,
private val call: AsyncThreadCall? = null,
private val run: (params: kotlin.Array<out Any?>?) -> Any?) : AsyncTask<Any?, Any?, Any?>()
//毫秒换成00:00:00
fun getCountTimeByLong(finishTime: Long, isNeedHour: Boolean): String
//时间戳转日期
fun longTimeToStr(time: Long?, pattern: String = "yyyy-MM-dd HH:mm"): String
//年月日转时间戳
fun ymdToLongTime(year: Int, month: Int, day: Int, isZeroTime: Boolean): Long
//年月日时分秒转时间戳
fun ymdHmToLongTime(year: Int, month: Int, day: Int, hourOfDay: Int, minute: Int): Long
//保留两位小数
fun keepTwoPoint(bigDecimal: String?): String
fun keepTwoPoint(bigDecimal: BigDecimal?): String
```
* **RetrofitHelper.obj**
retrofit工具类
```kotlin
//默认的创建网络的请求,数据会转为Bean
fun <T> createService(baseUrl: String, t: Class<T>, client: OkHttpClient? = null): T
// 有基本的使用功能,需要自定义转换器
fun <T> createBaseNet(baseUrl: String, apiClass: Class<T>, builder: ((Retrofit.Builder) -> Unit)? = null): T
//通过service发送请求,并回调
fun <T> sendRequest(request: retrofit2.Call<T>, success: (T) -> Unit, fail: ((Throwable?) -> Unit)? = null)
```
* **MessageBus.obj**
一个简单的仿EventBus,通过接口**MessageBusInterface**实现数据传递的监听。MvvmActivity,MvvmFragment,MvvmDialog默认已经注册封装,只需要实现方法** fun onMessageBus(event: Any?, code: Int)**即可监听到数据。
```kotlin
//注册
fun register(receiver: MessageBusInterface)
//移除注册
fun unRegister(receiver: MessageBusInterface)
//将值发送出去
//isSticky 新注册的第一个接口是否接受此数据
fun post(code: Int, event: Any?, isSticky: Boolean = false)
//赋值最新的一次值
//每次新添加的监听者,都可以接受到最新的一次值,之前注册的不会收到回调
fun postLastValue(code: Int, event: Any?)
//将值发送出去
//mark 指定需要接受本次推送值得接口(已经注册过的),post后新注册的无法接受到这个数据。
fun post(code: Int, event: Any?, isSticky: Boolean = false, vararg mark: Class<*>)
```
* **NoParamsLifecycleObserver**
实现这个接口的类,将会和实现了**LifecycleOwner**(比如activty,fragment)生命周期绑定
```kotlin
//实现了LifecycleOwner类调用此方法,注册
lifecycle.addObserver(@NonNull LifecycleObserver observer)
//实现了LifecycleOwner类调用此方法,移除注册
lifecycle.removeObserver(@NonNull LifecycleObserver observer)
```
* **WithParamsLifecycleObserver**
和上面的区别就是,几个回调带有参数
```kotlin
fun onCreate(lifecycleOwner: LifecycleOwner) {
}
fun onStart(lifecycleOwner: LifecycleOwner) {
}
fun onResume(lifecycleOwner: LifecycleOwner) {
}
fun onPause(lifecycleOwner: LifecycleOwner) {
}
fun onStop(lifecycleOwner: LifecycleOwner) {
}
fun onDestroy(lifecycleOwner: LifecycleOwner) {
}
fun onLifeChange(lifecycleOwner: LifecycleOwner, event: Lifecycle.Event) {
}
```
1
https://gitee.com/kotle/MvvmModule.git
git@gitee.com:kotle/MvvmModule.git
kotle
MvvmModule
MvvmModule
master

搜索帮助