这是一个MVI的Jetpack Compose Material3的基础项目,其中封装好了网络层,添加了一个简单的登录,存储,页面跳转的示例,使用Navigation进行页面的导航,遵循着MVI架构的规范对页面中的显示数据放在State中,交互相关的操作在Intent里,View通过对ViewModel发送Intent来修改状态从而响应View的变化,实现单向数据流的数据操作流程,使用hilt框架进行网络请求工具等注入,网络框架对retrofit2进行了简单的封装,使用flow进行网络请求流程的监听。其中用户的登录信息用DataStorePreferences进行存储。简单的信息,比如是否第一次进入软件,是否保存和自动登录等简单安全级别不高的状态值,使用mmkv进行存储。本项目没有过多的进行分包和封装,只内置了常用的一些业务逻辑,也可以作为MVI架构的参考来进行修改,主要是为减少学习成本,不用拿到一个架构就看各种别人自定义的封装内容。这是一个简单但是不简陋的基础项目。
- AGP:8.1.0
- Kotlin:1.8.10
- CompileSdk 33
- MinSdk 26
- JetpackComposeMaterial3
-
MMKV
-
DataStore-Preferences
- Retrofit2
- Cookie
- Hilt
- Navigation
- Icon+
- Systemuicontroller
├─activity
├─config
├─constant
├─di
├─model
│ ├─body
│ └─state
├─network
│ ├─api
│ └─res
├─ui
│ ├─components
│ ├─screen
│ │ ├─detail
│ │ ├─guide
│ │ ├─login
│ │ └─main
│ │ ├─home
│ │ └─user
│ └─theme
└─util
- activity:存放Activity内容,单activity的时候主要存放MainActivity
- config:存放DataStore,MMKV初始化,APP路由配置等
- constant:存放一些常量,例如网络请求的请求超时时间设定等
- di:存放Hilt框架的一些注入模块,比如RequestBuilder,DataStore等
- model:存放一些公共会使用到的类结构,比如请求体,公共的状态
- network:存在网络层的主要内容,例如响应映射类,api接口,网络构建者工具
- ui:主要存放view的内容,其中的components存放公共的一些组件组合函数,screen存放每个页面对应的view内容,theme存放app的主题,配色,字体等
- util:存放工具类
例如Login页面(.ui.screen.login)
LoginView:存放view的ui组合函数,主要是通过调用LoginView来进行Login页面的显示
LoginViewComponents:Login页面自己的自己部分ui组件
LoginViewIntent:存放LoginViewModel和相关的Intent
LoginViewState:存放Login页面上的数据相关状态,例如登录账号密码,是否记住密码,是否自动登录状态等
建议使用:通过hilt创建RequestBuilder模块,在ViewModel进行注入使用
RequestBuilder是网络工具的核心,使用getAPI进行APi接口的创建,然后调用对应的API获取对应execute传入给getResponse,getResponse会返回一个flow然后监听flow的数据流,其中会返回三种状态,请求开始Loding,请求成功,请求失败。然后进行对应的操作,要在线程中进行请求,所以建议在ViewModel中进行使用,使用官方的viewModelScope.launch{}创建协程作用域进行网络请求
LoginViewIntent中的LoginViewModel有登录的请求示例(已注释)
//LoginViewIntent.kt
//已在LoginViewModel的主构造函数中进行了注入
//协程中调用的请求
requestBuilder.apply {
//调用getResponse监听返回的flow
getResponse {
//调用getAPI传入API接口类型,并且调用函数,然后调用execute转为同步请求
getAPI(UserAPI::class).login().execute()
}.collect {//监听流发送出来的数据
when (it) {//提交到流中的数据是一个密封类,可以直接用when进行判断类型
is RequestStatus.Error -> {//请求失败
Log.e("TAG", "loginRequest:${it.errMsg} ${it.exception} ", )
}
RequestStatus.Loading -> {}//正在请求
is RequestStatus.Success -> {//网络请求成功
}
}
}
}
//RequestBuilder.kt
//请求会提交给flow的三种状态
sealed class RequestStatus<out T> {
data class Success<out T>(val data: T) : RequestStatus<T>()
data class Error(val exception: Exception, val errMsg: String) : RequestStatus<Nothing>()
object Loading : RequestStatus<Nothing>()
}