当前位置: 首页 > news >正文

Android 之 Kotlin 和 MVVM 架构的 Android 登录示例

项目结构​

app/
├── src/
│   ├── main/
│   │   ├── java/com/example/login/
│   │   │   ├── data/
│   │   │   │   ├── UserRepository.kt   # 数据仓库
│   │   │   │   └── model/User.kt        # 数据模型
│   │   │   ├── ui/
│   │   │   │   ├── LoginActivity.kt     # View 层
│   │   │   │   └── LoginViewModel.kt     # ViewModel 层
│   │   │   └── di/                      # 依赖注入(可选)
│   │   └── res/
│   │       └── layout/activity_login.xml

​1. Model 层:数据模型与仓库​

User.kt​ - 用户数据模型
data class User(val username: String,val password: String
)
UserRepository.kt​ - 数据仓库(模拟登录逻辑)
class UserRepository {// 模拟用户数据(实际项目中可能从网络/数据库获取)private val validUser = User("user@example.com", "123456")suspend fun login(username: String, password: String): Boolean {delay(1000) // 模拟网络请求延迟return username == validUser.username && password == validUser.password}
}

​2. ViewModel 层:业务逻辑与状态管理​

LoginViewModel.kt​ - 处理登录逻辑
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launchclass LoginViewModel(private val repository: UserRepository) : ViewModel() {// UI 状态(使用密封类封装)sealed class LoginState {object Idle : LoginState()object Loading : LoginState()data class Success(val user: User) : LoginState()data class Error(val message: String) : LoginState()}private val _loginState = MutableStateFlow<LoginState>(LoginState.Idle)val loginState: StateFlow<LoginState> = _loginStatefun login(username: String, password: String) {if (username.isEmpty() || password.isEmpty()) {_loginState.value = LoginState.Error("用户名或密码不能为空")return}_loginState.value = LoginState.LoadingviewModelScope.launch {try {val success = repository.login(username, password)if (success) {_loginState.value = LoginState.Success(User(username, password))} else {_loginState.value = LoginState.Error("用户名或密码错误")}} catch (e: Exception) {_loginState.value = LoginState.Error("网络请求失败: ${e.message}")}}}
}

关键设计​​ 

  • ​状态封装​​:使用 Sealed Class 明确区分不同 UI 状态(加载、成功、错误)。
  • ​协程作用域​​:通过 viewModelScope 自动取消后台任务,避免内存泄漏。
  • ​单向数据流​​:StateFlow 保证状态更新的一致性和可观察性。

3. View 层:UI 控制与数据绑定​

activity_login.xml​ - 布局文件(使用 Data Binding)
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variable name="viewModel" type="com.example.login.ui.LoginViewModel" /></data><LinearLayout><EditTextandroid:id="@+id/et_username"android:hint="用户名"android:text="@={viewModel.username}" /> <!-- 双向绑定 --><EditTextandroid:id="@+id/et_password"android:inputType="textPassword"android:hint="密码"android:text="@={viewModel.password}" /><Buttonandroid:text="登录"android:onClick="@{() -> viewModel.login()}" /> <!-- 绑定点击事件 --><ProgressBarandroid:visibility="@{viewModel.loading ? View.VISIBLE : View.GONE}" /><TextViewandroid:text="@{viewModel.errorMessage}" /> <!-- 显示错误信息 --></LinearLayout>
</layout>
LoginActivity.kt​ - Activity 实现
class LoginActivity : AppCompatActivity() {private lateinit var binding: ActivityLoginBindingprivate val viewModel: LoginViewModel by viewModels { LoginViewModelFactory(UserRepository()) }override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = DataBindingUtil.setContentView(this, R.layout.activity_login)binding.viewModel = viewModelbinding.lifecycleOwner = this // 启用生命周期感知// 监听登录状态变化viewModel.loginState.onEach { state ->when (state) {is LoginViewModel.LoginState.Success -> startActivity(Intent(this, MainActivity::class.java))is LoginViewModel.LoginState.Error -> Toast.makeText(this, state.message, Toast.LENGTH_SHORT).show()else -> {} // 忽略 Loading/Idle}}.launchIn(lifecycleScope) // 使用协程收集状态}
}

​关键功能

  • ​Data Binding​​:减少 findViewById 和手动更新 UI 的样板代码。
  • ​生命周期感知​​:通过 lifecycleOwner 确保数据绑定仅在活跃状态下更新。
  • ​状态驱动 UI​​:根据 loginState 自动切换界面(如显示加载条、错误提示)。

总结​

组件职责技术实现
​Model​数据获取与验证Repository + 协程
​ViewModel​状态管理、逻辑处理StateFlow + Sealed Class
​View​数据绑定、事件转发Data Binding + Lifecycle
http://www.lryc.cn/news/611165.html

相关文章:

  • 腾讯云对象存储服务COS
  • QtPromise第三方库的介绍和使用
  • 人工智能领域、图欧科技、IMYAI智能助手2025年1月更新月报
  • ubuntu24中部署k8s 1.30.x-底层用docker
  • 相机拍摄的DNG格式照片日期如何修改?你可以用这款工具修改
  • Android异常信号处理详解
  • 【网络运维】Linux:系统启动原理与配置
  • Coze开源了!意味着什么?
  • 在Linux上部署RabbitMQ、Redis、ElasticSearch
  • 无监督学习聚类方法——K-means 聚类及应用
  • NFS CENTOS系统 安装配置
  • 走进“Mesh无线自组网”:开启智能家居和智慧工厂
  • 安科瑞智慧能源管理系统在啤酒厂5MW分布式光伏防逆流控制实践
  • uv与conda环境冲突,无法使用uv环境,安装包之后出现ModuleNotFoundError: No module named ‘xxx‘等解决方法
  • unity之 贴图很暗怎么办
  • 【STM32】HAL库中的实现(四):RTC (实时时钟)
  • python的教务管理系统
  • 江协科技STM32学习笔记1
  • Spring 的依赖注入DI是什么?
  • 【计算机网络】6应用层
  • PostgreSQL——函数
  • 【语音技术】什么是VAD
  • Windows 电脑远程访问,ZeroTier 实现内网穿透完整指南(含原理讲解)
  • NLP自然语言处理 03 Transformer架构
  • 人工智能-python-Sklearn 数据加载与处理实战
  • ChatGPT以及ChatGPT强化学习步骤
  • MLIR Bufferization
  • Linux驱动学习(八)设备树
  • 《手撕设计模式》系列导学目录
  • 防火墙安全策略练习