1、使用新的冷流方式刷新数据
This commit is contained in:
shenzuqiang 2026-03-12 09:24:14 +08:00
parent 7ca00b9626
commit db36d63082
14 changed files with 83 additions and 118 deletions

View File

@ -56,10 +56,7 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.img.rabbit.bean.request.ReportKey
import com.img.rabbit.bean.request.ReportRequest
import com.img.rabbit.bean.request.ReportType
import com.img.rabbit.components.CenterToast
import com.img.rabbit.bean.response.UniVersionEntity
import com.img.rabbit.components.GlobalToast
import com.img.rabbit.config.Constants
import com.img.rabbit.config.Constants.agreementUrl
@ -115,18 +112,36 @@ class MainActivity : ComponentActivity(), LoadingCallback {
val globalStateManager = remember { GlobalStateManager(context) }
val updateAppNotify by globalStateManager.globalUpdateNotifyFlow().collectAsState(initial = false)
val updateUniDownloadNotify by globalStateManager.globalUniDownloadNotifyFlow().collectAsState(initial = false)
val updateUserConfigNotify by globalStateManager.globalUserConfigNotifyFlow().collectAsState(initial = false)
val updateUniUpdateNotify by globalStateManager.globalUniUpdateNotifyFlow().collectAsState(initial = false)
val updateGlobalLoadingNotify by globalStateManager.isGlobalLoadingFlow().collectAsState(initial = false)
// val updateGlobalLoadingNotify by globalStateManager.isGlobalLoadingFlow().collectAsState(initial = false)
//重置状态信息(防止异常退出导致状态失效)
LaunchedEffect(Unit) {
globalStateManager.apply {
storeGlobalUpdateNotify(false)
storeGlobalUniDownloadNotify(false)
storeGlobalUserConfigNotify(false)
storeGlobalUniUpdateNotify(false)
storeGlobalLoading(false)
// storeGlobalLoading(false)
}
}
val isGlobalLoading by generalViewModel.isLoading.collectAsState()
var showUniDownloadDialog by remember { mutableStateOf(false) }
var downloadUniEntity by remember { mutableStateOf<UniVersionEntity?>(null) }
LaunchedEffect(Unit) {
GeneralViewModel.GlobalEventBus.events.collect { event ->
when (event) {
is GeneralViewModel.GlobalEvent.ShowUniDownloadNotify -> {
downloadUniEntity = event.entity
showUniDownloadDialog = true
}
is GeneralViewModel.GlobalEvent.ShowAppUpdateNotify -> {
// 处理 App 更新弹窗逻辑
}
// ... 处理其他事件
else -> {}
}
}
}
@ -187,9 +202,9 @@ class MainActivity : ComponentActivity(), LoadingCallback {
//提示下载小程序资源(在跳转指定页面时,未下载资源需要提示)
val progressWGTToPageState = remember { mutableFloatStateOf(0f) }
LaunchedEffect(updateUniDownloadNotify) {
if(updateUniDownloadNotify == true) {
UniAppUtils.currentDownloadUniMp?.let{
LaunchedEffect(showUniDownloadDialog) {
if(showUniDownloadDialog) {
downloadUniEntity?.let{
UniAppUtils.downloadReleaseWgt(
coroutineScope,
it,
@ -206,9 +221,7 @@ class MainActivity : ComponentActivity(), LoadingCallback {
progressWGTToPageState.floatValue = 1f
Log.i("HomeScreen", "DOWNLOAD_FINISH")
coroutineScope.launch {
globalStateManager.storeGlobalUniDownloadNotify(
false
)
showUniDownloadDialog = false
}
}
@ -217,9 +230,7 @@ class MainActivity : ComponentActivity(), LoadingCallback {
progressWGTToPageState.floatValue = -1f
Log.i("HomeScreen", "DOWNLOAD_FAIL")
coroutineScope.launch {
globalStateManager.storeGlobalUniDownloadNotify(
false
)
showUniDownloadDialog = false
}
}
@ -236,7 +247,7 @@ class MainActivity : ComponentActivity(), LoadingCallback {
onRelease = { isSuccess->
if(isSuccess){
//资源下载完成后,启动小程序到指定位置
val uniMpEntity = UniAppUtils.currentDownloadUniMp
val uniMpEntity = downloadUniEntity
if (uniMpEntity != null && UniAppUtils.isRelease(uniMpEntity.unimp_id)) {
UniAppUtils.startUniMpPage(
context = context,
@ -301,8 +312,8 @@ class MainActivity : ComponentActivity(), LoadingCallback {
}
//提示下载小程序资源(在跳转指定页面时,未下载资源需要提示)
if(updateUniDownloadNotify == true){
UniAppUtils.currentDownloadUniMp?.let {
if(showUniDownloadDialog){
downloadUniEntity?.let {
TipsUniMpToPageDialog(
title = "下载资源",
content1 = "需要下载完资源才能运行,请稍后...",
@ -388,7 +399,8 @@ class MainActivity : ComponentActivity(), LoadingCallback {
}
//全局加载提示
if (updateGlobalLoadingNotify == true) {
if(isGlobalLoading){
// if (updateGlobalLoadingNotify == true) {
Log.i("HomeScreen","isStartOn--->${System.currentTimeMillis()}")
Box(
modifier = Modifier
@ -423,7 +435,8 @@ class MainActivity : ComponentActivity(), LoadingCallback {
override fun showLoading() {
lifecycleScope.launch {
GlobalStateManager(this@MainActivity).storeGlobalLoading(true)
// GlobalStateManager(this@MainActivity).storeGlobalLoading(true)
generalViewModel.setLoading(true)
}
}
@ -431,7 +444,8 @@ class MainActivity : ComponentActivity(), LoadingCallback {
override fun hideLoading() {
lifecycleScope.launch {
delay(3000L)
GlobalStateManager(this@MainActivity).storeGlobalLoading(false)
// GlobalStateManager(this@MainActivity).storeGlobalLoading(false)
generalViewModel.setLoading(false)
}
}
}

View File

@ -482,8 +482,8 @@ fun HomeScreen(
if(!wgtExists){
//是否下载
scope.launch {
UniAppUtils.currentDownloadUniMp = uniVersion
GlobalStateManager(context).storeGlobalUniDownloadNotify(true)
GeneralViewModel.GlobalEventBus.emit(
GeneralViewModel.GlobalEvent.ShowUniDownloadNotify(uniVersion))
}
}else {
UniAppUtils.startUniMpPage(context = context, uniMpId = uniMpId, uniMpType = item.type, pagePath = item.url, reportViewModel = reportViewModel)

View File

@ -389,7 +389,7 @@ fun MineScreen(
if (!generalViewModel.api.isWXAppInstalled) {
CenterToast.show("未安装微信客户端")
}else if(userInfo != null){
viewModel.requestServiceLink(context, generalViewModel.api)
viewModel.requestServiceLink(generalViewModel.api)
}
},
verticalAlignment = Alignment.CenterVertically

View File

@ -22,17 +22,17 @@ class GlobalStateManager(
private val GLOBAL_USER_CONFIG_NOTIFY = booleanPreferencesKey("global_user_config_notify")
}
suspend fun storeGlobalLoading(value: Boolean) {
context.storeData.edit { preferences ->
preferences[GLOBAL_LOADING] = value
}
}
fun isGlobalLoadingFlow(): Flow<Boolean?> {
return context.storeData.data.map {
preferences ->
preferences[GLOBAL_LOADING]
}
}
// suspend fun storeGlobalLoading(value: Boolean) {
// context.storeData.edit { preferences ->
// preferences[GLOBAL_LOADING] = value
// }
// }
// fun isGlobalLoadingFlow(): Flow<Boolean?> {
// return context.storeData.data.map {
// preferences ->
// preferences[GLOBAL_LOADING]
// }
// }
suspend fun storeGlobalUpdateNotify(value: Boolean) {
@ -59,19 +59,6 @@ class GlobalStateManager(
}
}
suspend fun storeGlobalUniDownloadNotify(value: Boolean) {
context.storeData.edit { preferences ->
preferences[GLOBAL_UNI_DOWNLOAD_NOTIFY] = value
}
}
fun globalUniDownloadNotifyFlow(): Flow<Boolean?> {
return context.storeData.data.map {
preferences ->
preferences[GLOBAL_UNI_DOWNLOAD_NOTIFY]
}
}
suspend fun storeGlobalUserConfigNotify(value: Boolean) {
context.storeData.edit { preferences ->

View File

@ -53,8 +53,6 @@ object UniAppUtils {
//当前正在更新的小程序
var currentUpdateUniMp: UniVersionEntity? = null
//当前正在下载的小程序
var currentDownloadUniMp: UniVersionEntity? = null
//仅当跳转指定小程序时,才需要跳转指定位置
var currentUniMpJumpPatch: String? = null

View File

@ -19,8 +19,6 @@ class AccountBindViewModel : BaseViewModel() {
* 请求登录(验证码)
*/
fun requestUnBindByPhone(phone: String) {
isLoading.value = true // 开始加载
// 调用 API 获取数据
val jsonPhone = JsonObject()
jsonPhone.addProperty("phone", phone)
@ -41,7 +39,6 @@ class AccountBindViewModel : BaseViewModel() {
if(wechatCode.isEmpty()){
return
}
isLoading.value = true // 开始加载
PreferenceUtil.saveWxCode(wechatCode)
// 调用 API 获取数据
@ -65,7 +62,6 @@ class AccountBindViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "解绑失败" })
}
isLoading.value = false // 加载完成
}
}
}

View File

@ -20,7 +20,6 @@ class AccountManagerViewModel : BaseViewModel() {
val errorState = mutableStateOf<ErrorBean?>(null)
fun requestAccount() {
isLoading.value = true // 开始加载
mLaunch {
val response = ApiManager.serviceVo.account()
if (response.status) {
@ -29,13 +28,10 @@ class AccountManagerViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "获取账号失败..." })
}
isLoading.value = false // 开始加载
}
}
fun switchAccount(userId: String) {
isLoading.value = true // 开始加载
// 调用 API 获取数据
val jsonSwitch = JsonObject()
jsonSwitch.addProperty("user_id", userId)
@ -52,7 +48,6 @@ class AccountManagerViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "切换账号失败..." })
}
isLoading.value = false // 开始加载
}
}
}

View File

@ -5,18 +5,25 @@ import androidx.lifecycle.viewModelScope
import com.img.rabbit.components.CenterToast
import com.img.rabbit.provider.utils.NetworkUtils.globalNetworkStatus
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
open class BaseViewModel : ViewModel() {
var isShowMsg = mutableStateOf(false)
var msgContent = mutableStateOf("")
val isLoading = mutableStateOf(false)
private val _isLoading = MutableStateFlow(false)
val isLoading = _isLoading.asStateFlow()
fun setLoading(loading: Boolean) {
_isLoading.value = loading
}
fun mLaunch(block: suspend () -> Unit) {
if (!globalNetworkStatus) {
CenterToast.show("网络已断开,请检查网络连接")
isLoading.value = false // 加载完成
setLoading(false) // 加载完成
return
}
viewModelScope.launch(Dispatchers.IO) {

View File

@ -143,8 +143,6 @@ class BindViewModel : BaseViewModel() {
}
fun requestOneKeyLogin(gyuid: String, token: String) {
isLoading.value = true // 开始加载
// 调用 API 获取数据
val jsonOneKey = JsonObject()
@ -163,8 +161,6 @@ class BindViewModel : BaseViewModel() {
*/
fun requestCaptcha(phone: String) {
// 发送请求获取验证码
isLoading.value = true // 开始加载
mLaunch {
// 调用 API 获取数据
val jsonObject = JsonObject()
@ -176,7 +172,6 @@ class BindViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "获取验证码失败" })
}
isLoading.value = false // 加载完成
}
}
@ -184,8 +179,6 @@ class BindViewModel : BaseViewModel() {
* 请求登录(验证码)
*/
fun requestBindForCaptcha(phone: String, code: String) {
isLoading.value = true // 开始加载
// 调用 API 获取数据
val jsonPhone = JsonObject()
jsonPhone.addProperty("timestamp", captchaTimestamp.value)
@ -232,7 +225,6 @@ class BindViewModel : BaseViewModel() {
if(wechatCode.isEmpty()){
return
}
isLoading.value = true // 开始加载
PreferenceUtil.saveWxCode(wechatCode)
// 调用 API 获取数据
@ -258,12 +250,9 @@ class BindViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "登录失败" })
}
isLoading.value = false // 加载完成
}
}
enum class BindType(val type: Int,val desc: String){
FROM_PHONE(0,"手机号"),
FROM_WX(1,"微信")

View File

@ -15,7 +15,6 @@ class DeleteAccountViewModel : BaseViewModel() {
val errorState = mutableStateOf<ErrorBean?>(null)
fun deleteAccount() {
isLoading.value = true // 开始加载
mLaunch {
val response = ApiManager.serviceVo.userDestroy()
if (response.status) {
@ -26,7 +25,6 @@ class DeleteAccountViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "注销失败..." })
}
isLoading.value = false // 开始加载
}
}
}

View File

@ -63,7 +63,6 @@ class FeedbackViewModel : BaseViewModel() {
fun uploadImage(context: Context, uri: Uri) {
isLoading.value = true // 开始加载
mLaunch {
try {
val compressedUri = ImageUtils.imageCompressToUri(context, uri) ?: throw IOException("无法压缩图片")
@ -76,27 +75,22 @@ class FeedbackViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "上传失败" })
}
isLoading.value = false // 开始加载
}catch (e: IOException){
e.printStackTrace()
isLoading.value = false // 开始加载
}
}
}
fun batchDeleteImage(uris: List<Uri>) {
isLoading.value = true // 开始加载
uris.forEach {
deleteImage(it)
}
}
fun deleteImage(uri: Uri) {
isLoading.value = true // 开始加载
val fileId = uploadFiles.firstOrNull { it.uri == uri }?.fileEntity?.id
if(fileId.isNullOrEmpty()){
isLoading.value = false // 开始加载
return
}
mLaunch {
@ -106,12 +100,10 @@ class FeedbackViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "删除失败" })
}
isLoading.value = false // 开始加载
}
}
fun submitFeedback(requestBody: RequestBody) {
isLoading.value = true // 开始加载
mLaunch {
val response = ApiManager.serviceVo.feedback(requestBody)
if (response.status) {
@ -119,7 +111,6 @@ class FeedbackViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "提交失败..." })
}
isLoading.value = false // 开始加载
}
}

View File

@ -15,6 +15,7 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.img.rabbit.bean.response.UniVersionEntity
import com.img.rabbit.config.Constants
import com.img.rabbit.provider.api.ApiManager
import com.img.rabbit.provider.storage.PreferenceUtil
@ -24,6 +25,8 @@ import com.tencent.mm.opensdk.constants.ConstantsAPI
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
@SuppressLint("ObsoleteSdkInt")
class GeneralViewModel: BaseViewModel(){
@ -38,6 +41,23 @@ class GeneralViewModel: BaseViewModel(){
private val _isNavigationBarVisible = MutableLiveData<Boolean>()
val isNavigationBarVisible: LiveData<Boolean> = _isNavigationBarVisible
// 可以定义一个事件密封类,方便扩展
sealed class GlobalEvent {
data class ShowUniDownloadNotify(val entity: UniVersionEntity) : GlobalEvent()
data class ShowUniUpdateNotify(val entity: UniVersionEntity) : GlobalEvent()
object ShowAppUpdateNotify : GlobalEvent()
}
object GlobalEventBus {
// replay = 0 确保事件是瞬时的,不会给新订阅者发送旧事件
private val _events = MutableSharedFlow<GlobalEvent>(extraBufferCapacity = 64)
val events = _events.asSharedFlow()
suspend fun emit(event: GlobalEvent) {
_events.emit(event)
}
}
private val connectivityManager =
HeadParamUtils.applicationContext?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

View File

@ -45,7 +45,6 @@ class LoginViewModel : BaseViewModel() {
private val TAG = "LoginViewModel"
private val ONEKEY_TAG = "OneKeyLoginViewModel"
//private lateinit var api: IWXAPI
var isLoginWxAuthor = false
val authInfoForAlipay: MutableState<String> = mutableStateOf("")
@ -62,18 +61,9 @@ class LoginViewModel : BaseViewModel() {
}
// 登录验证码发送时间戳
val captchaTimestamp = mutableStateOf("")
private val isGYUIDValid = mutableStateOf(false)
var oneKeyPreLogin: OnekeyPreLogin? = null
// 是否同意政策协议
private val _policyAgreement = mutableStateOf(true)
val isPolicyAgreement: State<Boolean> = _policyAgreement
@ -132,7 +122,6 @@ class LoginViewModel : BaseViewModel() {
}else{
Log.w("LoginViewModel", "获取配置失败: code=${response.code}, message=${response.message}")
}
isLoading.value = false // 加载完成
}
}
@ -222,8 +211,6 @@ class LoginViewModel : BaseViewModel() {
}
fun requestOneKeyLogin(gyuid: String, token: String) {
isLoading.value = true // 开始加载
// 调用 API 获取数据
val jsonOneKey = JsonObject()
@ -244,8 +231,6 @@ class LoginViewModel : BaseViewModel() {
*/
fun requestCaptcha(phone: String) {
// 发送请求获取验证码
isLoading.value = true // 开始加载
mLaunch {
// 调用 API 获取数据
val jsonObject = JsonObject()
@ -257,7 +242,6 @@ class LoginViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "获取验证码失败" })
}
isLoading.value = false // 加载完成
}
}
@ -265,8 +249,6 @@ class LoginViewModel : BaseViewModel() {
* 请求登录(验证码)
*/
fun requestLoginForCaptcha(phone: String, code: String) {
isLoading.value = true // 开始加载
// 调用 API 获取数据
val jsonPhone = JsonObject()
jsonPhone.addProperty("timestamp", captchaTimestamp.value)
@ -309,7 +291,6 @@ class LoginViewModel : BaseViewModel() {
if(code.isEmpty()){
return null
}
isLoading.value = true // 开始加载
PreferenceUtil.saveWxCode(code)
// 调用 API 获取数据
@ -329,8 +310,6 @@ class LoginViewModel : BaseViewModel() {
* 请求支付宝登录参数
*/
fun requestAliPayAuthParam(context: Context) {
isLoading.value = true // 开始加载
mLaunch {
val response = ApiManager.serviceVo.getAlipayAuthParam()
val data = response.data
@ -338,7 +317,6 @@ class LoginViewModel : BaseViewModel() {
authorAlipay(context = context,authParam = param)
authInfoForAlipay.value = param
isLoading.value = false // 加载完成
}
}
@ -399,8 +377,6 @@ class LoginViewModel : BaseViewModel() {
if(authCode.isEmpty()){
return null
}
isLoading.value = true // 开始加载
// 调用 API 获取数据
val jsonWx = JsonObject()
jsonWx.addProperty("auth_code", authCode)//code
@ -425,7 +401,6 @@ class LoginViewModel : BaseViewModel() {
}else{
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "登录失败" })
}
isLoading.value = false // 加载完成
}
}
@ -445,7 +420,6 @@ class LoginViewModel : BaseViewModel() {
*/
@OptIn(DelicateCoroutinesApi::class)
fun requestLogout() {
isLoading.value = true // 开始加载
mLaunch {
val response = ApiManager.serviceVo.logout()
if (response.status) {
@ -454,7 +428,6 @@ class LoginViewModel : BaseViewModel() {
} else {
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "退出登录失败" })
}
isLoading.value = false // 加载完成
}
}

View File

@ -1,6 +1,5 @@
package com.img.rabbit.viewmodel
import android.content.Context
import com.img.rabbit.bean.response.ServiceWxLinkEntity
import com.img.rabbit.provider.api.ApiManager
import com.tencent.mm.opensdk.constants.Build
@ -11,18 +10,16 @@ class MineViewModel : BaseViewModel() {
private val TAG = "MineViewModel"
//请求客服连接
fun requestServiceLink(context: Context,api: IWXAPI){
fun requestServiceLink(api: IWXAPI){
mLaunch {
val response = ApiManager.serviceVo.wxService()
if (response.status) {
contactClientService(response.data,context,api)
} else {
contactClientService(response.data, api)
}
isLoading.value = false // 加载完成
}
}
private fun contactClientService(data: ServiceWxLinkEntity,context: Context,api: IWXAPI) {
private fun contactClientService(data: ServiceWxLinkEntity, api: IWXAPI) {
if (api.wxAppSupportAPI >= Build.SUPPORT_OPEN_CUSTOMER_SERVICE_CHAT) {
val req = WXOpenCustomerServiceChat.Req()
req.corpId = data.corpid