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

Android MVVM架构实战:XML与Compose的Hilt+ViewModel整合开发

下面我将详细介绍如何在Android项目中结合使用XML或Compose、Hilt依赖注入和ViewModel来实现MVVM架构模式。

MVVM架构核心组件

  1. Model: 数据层,负责数据获取和存储
  2. View: UI层,XML布局或Compose组件
  3. ViewModel: 业务逻辑层,连接View和Model

项目配置

1. 添加依赖项 (build.gradle)

// Hilt
implementation "com.google.dagger:hilt-android:2.48"
kapt "com.google.dagger:hilt-android-compiler:2.48"

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"

// 如果是Compose
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2"

// LiveData (XML中使用)
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"

// Compose (可选)
implementation "androidx.compose.runtime:runtime-livedata:1.5.4"

使用Hilt进行依赖注入

1. 设置Hilt Application

@HiltAndroidApp
class MyApplication : Application()

2. 创建Module提供依赖

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    @Provides
    @Singleton
    fun provideRepository(): MyRepository {
        return MyRepositoryImpl()
    }
}

实现MVVM架构

1. Model层 (Repository)

interface MyRepository {
    suspend fun fetchData(): String
    fun getLiveData(): LiveData<String>
}

class MyRepositoryImpl @Inject constructor() : MyRepository {
    private val _data = MutableLiveData<String>("Initial Data")
    
    override suspend fun fetchData(): String {
        // 模拟网络请求
        delay(1000)
        _data.postValue("Fetched Data")
        return "Fetched Data"
    }
    
    override fun getLiveData(): LiveData<String> = _data
}

2. ViewModel层

@HiltViewModel
class MyViewModel @Inject constructor(
    private val repository: MyRepository
) : ViewModel() {
    private val _uiState = MutableStateFlow("")
    val uiState = _uiState.asStateFlow()
    
    val liveData = repository.getLiveData()
    
    fun fetchData() {
        viewModelScope.launch {
            _uiState.value = "Loading..."
            val result = repository.fetchData()
            _uiState.value = result
        }
    }
}

XML实现方式

1. XML布局 (res/layout/activity_xml.xml)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
        
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fetch Data"/>
</LinearLayout>

2. Activity实现

@AndroidEntryPoint
class XmlActivity : AppCompatActivity() {
    private lateinit var binding: ActivityXmlBinding
    private val viewModel: MyViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityXmlBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // 观察LiveData (XML方式)
        viewModel.liveData.observe(this) { data ->
            binding.textView.text = data
        }
        
        // 观察StateFlow (也可以使用)
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect { state ->
                    binding.textView.text = state
                }
            }
        }
        
        binding.button.setOnClickListener {
            viewModel.fetchData()
        }
    }
}

Compose实现方式

1. Compose Activity

@AndroidEntryPoint
class ComposeActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyAppTheme {
                ComposeScreen()
            }
        }
    }
}

@Composable
fun ComposeScreen(viewModel: MyViewModel = hiltViewModel()) {
    val uiState by viewModel.uiState.collectAsState()
    val liveDataValue by viewModel.liveData.observeAsState("")
    
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "StateFlow: $uiState")
        Text(text = "LiveData: $liveDataValue")
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { viewModel.fetchData() }) {
            Text("Fetch Data")
        }
    }
}

数据同步策略

  1. 单一数据源:所有数据来自Repository
  2. 状态集中管理:ViewModel是唯一的状态持有者
  3. 数据流向
    • UI事件 → ViewModel → Repository
    • 数据变化 ← Repository ← ViewModel ← UI

最佳实践

  1. ViewModel职责

    • 处理业务逻辑
    • 管理UI状态
    • 协调数据请求
  2. View职责

    • 显示数据
    • 收集用户输入
    • 尽量不包含业务逻辑
  3. Hilt使用建议

    • 使用@Inject构造函数注入简单依赖
    • 使用Module提供复杂依赖
    • Activity/Fragment使用@AndroidEntryPoint
    • Compose使用hiltViewModel()
  4. 状态管理选择

    • XML优先使用LiveData
    • Compose优先使用StateFlow/State
    • 可以同时暴露两种形式供不同UI使用

这种架构结合了MVVM模式的优势,通过Hilt简化了依赖管理,同时兼容传统的XML和现代的Compose两种UI实现方式,非常适合渐进式迁移的项目。

相关文章:

  • 思考力提升的黄金标准:广度、深度与速度的深度剖析
  • 【软考系统架构设计师】系统架构设计知识点
  • 5.11 GitHub API调试五大高频坑:从JSON异常到异步阻塞的实战避坑指南
  • oracle命令上下左右键无法使用如何解决?
  • vue工程中路由导致的循环依赖问题
  • 使用 IP 代理改 IP 后注意事项如何防封号
  • OpenCV 进阶实战与技巧——图像处理的全面解析
  • Spring MVC 获取请求头参数详解
  • 【HarmonyOS 5】敏感信息本地存储详解
  • 数据结构---B树
  • decompiled.class file bytecode version50(java 6)
  • 分页查询列表每页1000条的优化
  • day1 初识MySQL
  • 词袋模型和TF-IDF(数学公式推导、手动实现、调库使用、示例:使用词袋模型处理多个文档)详解
  • 【前端工程化】-【vue2-ele项目升级】
  • error: failed to run custom build command for `yeslogic-fontconfig-sys v6.0.0`
  • docker 安装 Gitlab
  • 【go】--编译
  • Android基础教程 - 学习完成记录
  • UI基础(1)
  • 上海明后天将迎强风大雨,陆地最大阵风7~9级
  • 黄仁勋:中国AI市场将达500亿美元,美国企业若无法参与是巨大损失
  • 默茨当选德国总理
  • 马上评|独生子女奖励不能“私了”,政府诚信是第一诚信
  • 消失的日本中年劳动者:任何人都有与社会脱节的风险
  • 医生李某某饮酒上班?重庆长寿区人民医院:正在调查,将严肃处理