安卓软件开发:Jetpack Compose Material3 结合 MVI 架构的模块化架构设计和实践

2024-10-10 13:53:12 浏览数 (6)

2024年已经过半,作为一名聋人独立开发者,我常常反思这半年的进步和收获。在这篇文章中,我分享如何使用 Jetpack ComposeMaterial3 结合 MVI(Model-View-Intent) 架构设计一个模块化的Android应用。无论你是新手开发者,还是有经验的安卓开发人员,相信这篇文章都会对你有所帮助。

一、什么是 MVI 架构?

MVI 是 Model-View-Intent 的缩写,MVI 架构主要有三个核心部分:

  1. Model (模型):数据层,用于表示应用的状态,可以是从数据库、网络请求等获取的数据。
  2. View (视图):用户界面层,展示应用的 UI,响应用户的交互。
  3. Intent (意图):用户的交互事件或系统触发的操作,会导致 Model 的变化,最终反映到 View 上。

二、模块化架构设计

项目划分为以下几个模块:

  1. UI 层:负责界面渲染和用户交互逻辑。
  2. 数据层:管理数据获取、存储、处理(包括与网络和数据库的交互)。
  3. 业务逻辑层(ViewModel/Intent):连接 UI 和数据层,处理业务逻辑和状态管理。

采用的架构是 MVI(Model-View-Intent),在应用中的状态是不可变的,数据流是单向的,让 UI 的变化是可预测的。

三、项目结构

项目基于模块化设计,按照以下目录划分:

代码语言:java复制
com.nim.mviapp/
├── data/                     # 数据层
│   ├── repository/            # 数据仓库逻辑
│   ├── model/                 # 数据模型
│   └── database/              # Room数据库
│
├── ui/                       # UI 层
│   ├── theme/                 # Material3 主题
│   ├── component/             # 可复用的 UI 组件
│   └── screen/                # 页面定义,如HomeScreen等
│
├── viewmodel/                 # 业务逻辑层 (Intent   ViewModel)
│   └── WishViewModel.kt       # 处理业务逻辑及状态管理
│
└── MainApplication.kt         # 应用入口

四、模块功能解析

4.1 数据层

数据层采用 Repository Pattern,统一管理数据的来源。通过 Room 进行本地存储,使用 Flow 处理数据流,为了方便是 MVI 中的单向数据流保持一样。

代码语言:java复制
class WishRepository(private val wishDao: WishDao) {
    fun getWishes(): Flow<List<Wish>> = wishDao.getAllWishes()

    suspend fun addWish(wish: Wish) {
        wishDao.addAWish(wish)
    }
    suspend fun updateWishLikedStatus(wish: Wish, isLiked: Boolean) {
        wish.isLiked = isLiked
        wishDao.updateWish(wish)  
    }
    // 其他CRUD操作...
}

4.2 业务逻辑层 (Intent ViewModel)

MVI 中,用户的每个操作都会包装成 Intent,然后通过 ViewModel 处理。ViewModel 管理数据层的交互,还负责保持 UI 状态的同步。

代码语言:java复制
class WishViewModel(private val repository: WishRepository) : ViewModel() {

    val wishes: LiveData<List<Wish>> = repository.getWishes().asLiveData()

    fun addWish(wish: Wish) {
        viewModelScope.launch {
            repository.addWish(wish)
        }
    }
    // 新增的点赞状态更新方法
    fun updateWishLikedStatus(wish: Wish, isLiked: Boolean) {
        viewModelScope.launch {
            repository.updateWishLikedStatus(wish, isLiked)
        }
    }
    // 其他Intent的处理逻辑...
}

每个 Intent 都会触发相应的状态更新。

4.3 UI 层

UI 层通过 Jetpack ComposeMaterial3 构建应用 UI。借助 Compose 声明式的设计模式,可以轻松创建可复用的组件,结合 MVI 确保状态变化时界面自动更新。

代码语言:java复制
@Composable
fun HomeScreen(viewModel: WishViewModel) {
    val wishes by viewModel.wishes.observeAsState(initial = emptyList())

    LazyColumn {
        items(wishes) { wish ->
            Text(text = wish.title)
        }
    }
}

View 始终通过 IntentViewModel 交互,UI 渲染通过不可变的状态进行。

五、页面导航的实现

Jetpack Compose 提供了内置的导航库,帮助我们管理应用的页面跳转。页面之间的导航逻辑放在 MainScreen 中:

代码语言:java复制
@Composable
fun MainScreen() {
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "home") {
        composable("home") { HomeScreen(navController) }
        composable("detail/{id}") { backStackEntry ->
            val id = backStackEntry.arguments?.getString("id")
            DetailScreen(navController, id)
        }
    }
}

这样设计可以实现页面的解耦,减少依赖。

六、状态管理与数据流

状态是不可变的,每个操作都会产生一个新的状态。以下是一个状态驱动 UI 更新的例子:

代码语言:java复制
@Composable
fun WishItem(viewModel: WishViewModel, wish: Wish) {
    var isLiked by remember { mutableStateOf(false) }

    Column {
        Text(text = wish.title)
        IconButton(onClick = {
                    isLiked = !isLiked
                    viewModel.updateWishLikedStatus(wish, isLiked)  // 调用 ViewModel 方法更新点赞状态
          }) {
            Icon(imageVector = Icons.Default.Favorite, tint = if (isLiked) Color.Red else Color.Gray)
        }
    }
}

每当用户点击图标,状态 isLiked 发生变化,UI 会根据新的状态自动重绘。

七、总结

这种模块化设计架构极大地提升了应用的可维护性和扩展性。对于复杂项目而言,采用 MVI 这种单向数据流的架构设计可以减少状态管理的混乱,确保每一次状态变化都是可预测且可控的。

有任何问题欢迎提问,感谢大家阅读 )

0 人点赞