android compose 实现全局网络加载提示

1.定义一个网络消息类

data class HttpState(
data class HttpState(

    var show: Boolean = false,

    var isLoading: Boolean = false,
    /**
     * 响应编码
     */
    var code: String = "",
    /**
     * 响应的业务处理结果
     */
    var success: Boolean = true,
    /**
     * 响应的消息
     */
    val message: String? = null,
) {

    companion object {

        fun state(isLoading: Boolean, code: String, success: Boolean, message: String?): HttpState {
            return HttpState(
                show = true,
                isLoading = isLoading,
                code = code,
                success = success,
                message = message
            )
        }

        fun fail(message: String): HttpState {
            return HttpState(show = true, success = false, message = message)
        }
    }
}

2.定义一个基础viewModel 实现统一的网络方法请求

/**
 * @author Sun
 */
abstract class UnitMBViewModel : ViewModel() {

    val RED_WRITE_PERMISSIONS: MutableList<String> = mutableListOf()

    init {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) {
            RED_WRITE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE)
            RED_WRITE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
//            RED_WRITE_PERMISSIONS.add(Manifest.permission.MANAGE_EXTERNAL_STORAGE)
//        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            RED_WRITE_PERMISSIONS.add(Manifest.permission.READ_MEDIA_IMAGES)
            RED_WRITE_PERMISSIONS.add(Manifest.permission.READ_MEDIA_AUDIO)
            RED_WRITE_PERMISSIONS.add(Manifest.permission.READ_MEDIA_VIDEO)
        }
    }

    @Inject
    lateinit var preferences: UnitMBPreferences

    var httpState by mutableStateOf(HttpState())

    var confirmState by mutableStateOf(UConfirmState())

    var currentUser: UserInfo
        get() {
            val value = this.preferences.getString(UnitMBEnvironment.USER_INFO)
            return Gson().fromJson(value, UserInfo::class.java)
        }
        set(value) {
            this.preferences.putString(UnitMBEnvironment.USER_INFO, value.toString())
        }
    val token: String
        get() {
            return preferences.getString(UnitMBEnvironment.USER_TOKEN)
        }

    fun exitLogin(navController: NavController) {
        preferences.clearData()
        navController.navigate(Routes.Login.route)
    }

    fun closeHttpState() {
        httpState = HttpState()
    }

    fun closeConfirm() {
        confirmState = UConfirmState()
    }

    protected fun confirm(
        type: UConfirmType = UConfirmType.PRIMARY,
        title: String,
        message: String,
        confirm: () -> Unit = { }
    ) {
        confirmState = UConfirmState.show(type, title, message, confirm)
    }
    /**
    *   网络状态监听
    */
    protected suspend fun <D> network(
        loading: Boolean = true,
        request: suspend () -> UnitMBResponse<D>,
    ): D? {
        if (loading) {
            httpState = HttpState.state(true, "0", true, "加载中")
        }
        return try {
            val response = request()
            httpState = HttpState.state(false, response.code, response.success, response.message)
            response.data
        } catch (e: Exception) {
            e.printStackTrace()
            if (e is ConnectException) {
                httpState = HttpState.state(false, "-1", false, "网络请求异常")
            } else if (e is HttpException) {

                when (e.code()) {
                    401 -> httpState = HttpState.state(
                        false,
                        e.code().toString(),
                        false,
                        e.response()?.errorBody()?.string()
                    )

                    403 -> httpState = HttpState.state(
                        false,
                        HttpError.Forbidden.code,
                        false,
                        HttpError.Forbidden.message
                    )

                    404 -> httpState = HttpState.state(
                        false,
                        HttpError.NotFound.code,
                        false,
                        HttpError.NotFound.message
                    )

                    500 -> httpState = HttpState.state(
                        false, HttpError.ServerError.code, false, HttpError.ServerError.message
                    )
                }

            } else {
                httpState = HttpState.state(false, "-1", false, "网络请求异常")
            }
            null
        }
    }
}

3.在业务viewModel使用

@HiltViewModel
class HomeViewModel @Inject constructor(
    private val repository: HomeRepository
) : UnitMBViewModel() {
    /**
     *
     */
    var searchValue by mutableStateOf("")

    /**
     * 用户信息
     */
    var userInfo: UserInfo by mutableStateOf(UserInfo())

    /**
     * 获取用户信息
     */
    suspend fun getUserInfo() {
        val data = network(false) { repository.getUserInfo() }
        if (data != null) {
            userInfo = data
            currentUser = data
        }
    }
}

4.使用 Scaffold 组件 snackbarHost 监听网络状态更新界面提示信息

@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
fun HomePageView(navController: NavController, homeViewModel: HomeViewModel) {

    LaunchedEffect(true) {
        homeViewModel.getUserInfo()
    }

    Scaffold(containerColor = colorResource(R.color.dark), snackbarHost = {
        UStatePrompt(homeViewModel, navController)
    }, topBar = {
        TopAppBar(colors = TopAppBarDefaults.topAppBarColors(Color.Transparent), title = {
            Text(
                text = homeViewModel.userInfo.orgName, color = colorResource(R.color.gray)
            )
        }, actions = {
            IconButton(onClick = {
                navController.navigate(Routes.Setting.route)
            }) {
                Icon(
                    Icons.Rounded.Settings,
                    contentDescription = null,
                    tint = colorResource(R.color.primary)
                )
            }

        })
    }) { innerPadding ->
.....

5.自定义 snackbarHost 组件 实现自定的 提示框信息

@Composable
fun UStatePrompt(viewModel: UnitMBViewModel, navController: NavController) {

    val confirm = viewModel.confirmState

    val httpState = viewModel.httpState

    if (confirm.show) {
        Dialog(onDismissRequest = {}) {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .clip(RoundedCornerShape(8.dp))
                    .background(Color.White)
                    .padding(16.dp),
                verticalArrangement = Arrangement.spacedBy(6.dp)
            ) {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.spacedBy(6.dp)
                ) {
                    Icon(
                        modifier = Modifier.size(28.dp),
                        imageVector = Icons.Default.Info,
                        contentDescription = "",
                        tint = if (UConfirmType.DANGER == confirm.type) {
                            colorResource(R.color.danger)
                        } else {
                            colorResource(R.color.primary)
                        }
                    )
                    Text(
                        text = confirm.title, fontSize = 16.sp, fontWeight = FontWeight.Bold
                    )
                }
                Text(text = confirm.message)
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.spacedBy(6.dp, Alignment.End),
                ) {
                    TextButton(onClick = {
                        viewModel.closeConfirm()
                    }) {
                        Text(
                            text = "取消",
                            fontWeight = FontWeight.Bold,
                            color = colorResource(R.color.dark_gray)
                        )
                    }
                    TextButton(onClick = {
                        viewModel.closeConfirm()
                        confirm.confirm();
                    }) {
                        Text(
                            text = "确定",
                            fontWeight = FontWeight.Bold,
                            color = if (UConfirmType.DANGER == confirm.type) {
                                colorResource(R.color.danger)
                            } else {
                                colorResource(R.color.primary)
                            }
                        )
                    }
                }
            }
        }
    } else if (httpState.show) {
        if (httpState.isLoading) {
            Dialog(onDismissRequest = {}) {
                Box(
                    modifier = Modifier
                        .size(120.dp)
                        .clip(RoundedCornerShape(8.dp))
                        .background(Color.White), contentAlignment = Alignment.Center
                ) {
                    CircularProgressIndicator(
                        modifier = Modifier.size(48.dp),
                        color = MaterialTheme.colorScheme.primary,
                        trackColor = MaterialTheme.colorScheme.surfaceVariant,
                    )
                }
            }
        } else if (!httpState.success && httpState.message != null) {
            Dialog(onDismissRequest = {}) {
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .clip(RoundedCornerShape(8.dp))
                        .background(Color.White)
                        .padding(16.dp),
                    verticalArrangement = Arrangement.spacedBy(6.dp)
                ) {
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(6.dp)
                    ) {
                        Icon(
                            modifier = Modifier.size(28.dp),
                            imageVector = Icons.Default.Error,
                            contentDescription = "",
                            tint = colorResource(R.color.danger)
                        )
                        Text(
                            text = "错误", fontSize = 16.sp, fontWeight = FontWeight.Bold
                        )
                    }
                    Text(text = httpState.message)
                    TextButton(modifier = Modifier.align(Alignment.End), onClick = {
                        viewModel.closeHttpState()
                        if (httpState.code == HttpError.Unauthorized.code) {
                            viewModel.exitLogin(navController)
                        }
                    }) {
                        Text(
                            text = "确定",
                            fontWeight = FontWeight.Bold,
                            color = colorResource(R.color.danger)
                        )
                    }
                }
            }
        } else if (httpState.success && httpState.message != null) {
            Toast.makeText(LocalContext.current, httpState.message, Toast.LENGTH_SHORT).show()
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值