(2022.10.17) 新增MVI
该框架便于快速搭建MVVM应用
- 基于Retrofit+LiveData(Flow)+协程的网络请求
- 封装view布局状态切换
- 带有ViewBinding的BaseActivity和BaseFragment
- 带有懒加载的BaseFragment
-
基于Flow的Bus框架(类似EventBus)
使用:
1.xml中定义:
<!--StatusLayout初始化时有且只能有一个子View-->
<cn.ondu.basecommon.view.StatusLayout android:id="@+id/fl_content"
app:view_loading="@layout/view_loading" app:view_empty="@layout/view_empty"
app:view_error="@layout/view_error" app:load_default="content"
android:layout_width="match_parent" android:layout_height="match_parent">
<!--内容布局-->
<LinearLayout android:id="@+id/ll_content" android:layout_width="match_parent"
android:layout_height="match_parent" android:orientation="vertical" />
</cn.ondu.basecommon.view.StatusLayout>
2.代码调用:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mViewBinding.flStatus.showContentView()
mViewBinding.flStatus.showEmptyView()
mViewBinding.flStatus.showErrorView()
mViewBinding.flStatus.showLoadingView()
//获取当前状态
mViewBinding.flStatus.loadStatus
}
tag:当前状态分为:
enum class LoadStatus(val showType: Int) {
LOADING(0),
ERROR(1),
EMPTY(2),
CONTENT(3)
}
BaseBean需要实现IBaseBean接口
data class BaseBean<T>(val errorCode: Int, val errorMsg: String, val data: T) : IBaseBean<T> {
override fun errorCode(): Int = errorCode
override fun errorMsg(): String = errorMsg
override fun data(): T = data
override fun isSuccess(): Boolean = errorCode == Config.HTTP_SUCCESS_CODE
}
ViewModel,Repository分别继承BaseViewModel和BaseRepository
Repository中
class MainRepo : BaseRepository() {
suspend fun articleList() = parsData {
HttpClient.createApi(Api::class.java).articleList()
}
}
ViewModel中
class MainViewModel : BaseViewModel() {
private val mRepo by lazy { MainRepo() }
fun articleList() = httpToLiveData { mRepo.articleList() }
}
Activity中
private val mViewModel by viewModels<MainViewModel>()
private fun startHttp() {
mViewModel.articleList().observe(this, Observer {
it.onStart {}
.onSuccess { data -> }
.onError { code, message -> }
.onFinish {}
})
}
当然,你也可以
private fun startHttp() {
mViewModel.articleList().observe(this, Observer {
when (it) {
is HttpStatus.LoadingStatus -> {}
is HttpStatus.SuccessStatus -> { data -> }
is HttpStatus.ErrorStatus -> { code, message -> }
is HttpStatus.FinishStatus -> {}
}
})
}
BaseRepository中仅对数据做脱壳处理
suspend fun <T> parsData(
block: suspend () -> IBaseBean<T>
): T {
val httpResult = withContext(Dispatchers.IO) {
block()
}
if (httpResult.isSuccess()) {
return httpResult.data()
} else {
throw HttpException(httpResult.errorCode(), httpResult.errorMsg())
}
}
可根据业务需求适当扩展Error枚举类
enum class Error(private val code: Int, private val err: String) {
UNKNOWN(1000, "请求失败,请稍后再试"),
PARSE_ERROR(1001, "Json解析错误,请稍后再试"),
NETWORK_ERROR(1002, "网络连接错误,请稍后重试"),
SSL_ERROR(1004, "证书出错,请稍后再试"),
TIMEOUT_ERROR(1006, "网络连接超时,请稍后重试");
fun getValue(): String {
return err
}
fun getKey(): Int {
return code
}
}
BaseViewModel中进行具体的请求状态分发:
protected fun <T> httpToLiveData(
block: suspend () -> T
) = liveData<HttpStatus<T>>(Dispatchers.Main) {
emit(HttpStatus.LoadingStatus())
try {
//repository里已经将异常抛出 这里直接捕获就行
emit(HttpStatus.SuccessStatus(block()))
} catch (error: Exception) {
error.printStackTrace()
val handleException = ExceptionHandle.handleException(error)
emit(HttpStatus.ErrorStatus(handleException.errCode, handleException.errorMsg))
} finally {
emit(HttpStatus.FinishStatus())
}
}
3.封装BaseActivity,BaseFragment等基类(具体查看源码)
注: 如果要在ViewPager里使用BaseFragment懒加载时FragmentPagerAdapter的behavior参数要传入BEHAVIOR_SET_USER_VISIBLE_HINT
4.封装常用util工具(具体查看源码)