Jetpack Compose 02 Compose + ViewModel UI和数据逻辑分离

当我们在项目中使用Jetpack Compose进行页面编写的时候,页面涉及到数据刷新,该如何实现UI和数据逻辑分离?本文通过使用Compose + ViewModel ,将在ViewModel中实现数据逻辑,解耦Compose。

实现逻辑:

1、启动Activity时,显示Splash页面;

2、Splash页面显示倒计时 跳过按钮,跳转到Guide页面;

3、倒计时结束后,自动跳转到Guide页面。

一、创建Splash页面

创建Splash页面,包含icon+版权文本+右上角倒计时 跳过按钮,倒计时数据可归于耗时数据,将放在viewmodel中实现。

SplashRoute.kt

Kotlin 复制代码
/*年轻人,只管向前看,不要管自暴自弃者的话*/
package com.composetest.page.splash

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.composetest.R
import com.composetest.ui.theme.ComposeTestTheme

/**
 * create by itz on 2024/10/10 15:59
 * desc :
 **/

@Composable
fun SplashRoute(toGuide: () -> Unit, toMain: () -> Unit) {
    // 创建ViewModel
    val viewModel: SplashViewModel = viewModel()

    // 需要观察的数据
    val timeDown = viewModel.timeDown
    val navigationGuide = viewModel.navigationGuide

    SplashScreen(
        timeDown = timeDown,
        navigationGuide = navigationGuide,
        toGuide = toGuide,
        toMain = toMain
    )
}

@Composable
fun SplashScreen(
    timeDown: Long = 0L,
    navigationGuide: Boolean = false,
    toGuide: () -> Unit = {},
    toMain: () -> Unit = {}
) {

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.White)
    ) {
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_background),
            contentDescription = null,
            modifier = Modifier
                .align(
                    Alignment.Center
                )
                .padding(bottom = 150.dp)
        )
        Text(
            text = "版权号:2024",
            modifier = Modifier
                .align(Alignment.BottomCenter)
                .padding(bottom = 30.dp),
            style = TextStyle(fontSize = 14.sp, color = Color.Gray)
        )

        Button(
            onClick = toMain, modifier = Modifier
                .align(Alignment.TopEnd)
                .padding(top = 16.dp, end = 16.dp)
        ) {
            Text(
                text = "跳过:$timeDown",
                style = TextStyle(fontSize = 14.sp)
            )
        }

    }

    if (navigationGuide) {
        // 只在首次创建时执行内部函数
        LaunchedEffect(key1 = true) {
            // toGuide()
            toMain()
        }
    }

}

@Preview
@Composable
fun SplashScreenPreview() {
    ComposeTestTheme {
        SplashScreen()
    }
}

二、创建SplashViewModel

1、将倒计时数据放在ViewModel中实现,主要有以下方面考虑:

1)Compose页面存在多次刷新的情况,如果在Compose中开启倒计时会出现多次创建;

2)旋转屏幕等非正常销毁Activity的场景下,会导致Activity销毁并重建,从而导致倒计时出现多次创建;而在这场景下ViewModel并不会销毁重建,故将倒计时放在ViewModel中能保证数据一致性;

3)Compose页面属于UI部分,不应该混合数据逻辑处理,将倒计时放在ViewModel中能降低View和逻辑的耦合度,便于后续维护。

2、实现方式

mutableStateOf 是 Jetpack Compose 中的一个函数,用于创建一个可变的状态变量,这个状态变量可以在 Composable 函数中被读取和修改。当状态变量的值发生变化时,与之相关的 Composable 会被自动重新绘制以反映最新的状态。故使用mutableStateOf修饰倒计时变量timeDown 。

SplashViewModel.kt

Kotlin 复制代码
/*年轻人,只管向前看,不要管自暴自弃者的话*/
package com.composetest.page.splash

import android.os.CountDownTimer
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel


/**
 * create by itz on 2024/10/11 16:36
 * desc :
 **/
class SplashViewModel : ViewModel() {
    private var timer: CountDownTimer? = null
    var timeDown by mutableStateOf(0L)
    var navigationGuide by mutableStateOf(false)

    init {
        startCountDown()
    }

    private fun startCountDown() {
        timer = object : CountDownTimer(3000, 1000) {
            /**
             * 倒计时执行
             */
            override fun onTick(millisUntilFinished: Long) {
                timeDown = millisUntilFinished / 1000
                Log.e("SplashRoute", "timeDown $timeDown")
            }

            /**
             * 倒计时结束
             */
            override fun onFinish() {
                navigationGuide = true
            }

        }.start()
    }

    fun next(): Unit {
        timer?.cancel()
        navigationGuide = true
    }

    override fun onCleared() {
        super.onCleared()
        timer?.cancel()
    }
}

至此,完成了Compose + ViewModel UI和数据逻辑分离,类似的网络+本地数据也一样,将其放在 ViewModel实现。

相关推荐
用户0273851840268 小时前
[Android]RecycleView的item用法
android
前行的小黑炭9 小时前
Android :为APK注入“脂肪”,论Android垃圾代码在安全加固中的作用
android·kotlin
帅得不敢出门10 小时前
Docker安装Ubuntu搭建Android SDK编译环境
android·ubuntu·docker
tangweiguo0305198710 小时前
Android Kotlin 动态注册 Broadcast 的完整封装方案
android·kotlin
fatiaozhang952710 小时前
浪潮CD1000-移动云电脑-RK3528芯片-2+32G-安卓9-2种开启ADB ROOT刷机教程方法
android·网络·adb·电脑·电视盒子·刷机固件·机顶盒刷机
前行的小黑炭11 小时前
Android 不同构建模式下使用不同类的例子:如何在debug模式和release模式,让其使用不同的类呢?
android·kotlin·gradle
andyguo11 小时前
AI模型测评平台工程化实战十二讲(第一讲:从手工测试到系统化的觉醒)
android
2501_9159214311 小时前
小团队如何高效完成 uni-app iOS 上架,从分工到工具组合的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview
幂简集成12 小时前
通义灵码 AI 程序员低代码 API 课程实战教程
android·人工智能·深度学习·神经网络·低代码·rxjava
2501_9160088913 小时前
uni-app iOS 文件管理与 itools 配合实战,多工具协作的完整流程
android·ios·小程序·https·uni-app·iphone·webview