18 KiB
18 KiB
应用架构最佳实践
良好的应用架构是Android应用开发的基础,它直接影响应用的可维护性、可测试性和可扩展性。本文档介绍Android应用架构设计的最佳实践。
目录
架构设计原则
1. 关注点分离(Separation of Concerns)
单一职责原则
// ✅ 好的设计:每个类只有一个职责
class UserRepository {
fun getUser(userId: String): User {
// 只负责数据获取
}
}
class UserViewModel : ViewModel() {
private val repository: UserRepository
fun loadUser(userId: String) {
// 只负责UI逻辑
viewModelScope.launch {
val user = repository.getUser(userId)
_user.value = user
}
}
}
// ❌ 不好的设计:一个类承担多个职责
class UserManager {
fun getUser(userId: String): User { }
fun saveUser(user: User) { }
fun displayUser(user: User) { } // UI逻辑不应该在这里
fun validateUser(user: User) { } // 业务逻辑不应该在这里
}
2. 依赖倒置原则(Dependency Inversion)
依赖接口而非实现
// ✅ 好的设计:依赖接口
interface UserRepository {
suspend fun getUser(userId: String): User
}
class UserRepositoryImpl(
private val apiService: ApiService,
private val localDataSource: UserLocalDataSource
) : UserRepository {
override suspend fun getUser(userId: String): User {
// 实现细节
}
}
class UserViewModel(
private val repository: UserRepository // 依赖接口
) : ViewModel() {
// ...
}
// ❌ 不好的设计:依赖具体实现
class UserViewModel(
private val repository: UserRepositoryImpl // 依赖具体实现
) : ViewModel()
3. 开闭原则(Open/Closed Principle)
对扩展开放,对修改关闭
// ✅ 好的设计:通过扩展添加功能
abstract class DataSource {
abstract suspend fun getData(): Data
}
class RemoteDataSource : DataSource() {
override suspend fun getData(): Data {
// 从远程获取数据
}
}
class LocalDataSource : DataSource() {
override suspend fun getData(): Data {
// 从本地获取数据
}
}
// 可以添加新的数据源而不修改现有代码
class CacheDataSource : DataSource() {
override suspend fun getData(): Data {
// 从缓存获取数据
}
}
4. 接口隔离原则(Interface Segregation)
使用小而专的接口
// ✅ 好的设计:小而专的接口
interface Readable {
fun read(): String
}
interface Writable {
fun write(data: String)
}
class FileManager : Readable, Writable {
override fun read(): String { }
override fun write(data: String) { }
}
// ❌ 不好的设计:大而全的接口
interface DataManager {
fun read(): String
fun write(data: String)
fun delete()
fun update()
fun search()
// 太多方法,违反接口隔离原则
}
分层架构
1. 三层架构
表现层(Presentation Layer)
// UI层:Activity/Fragment
class UserActivity : AppCompatActivity() {
private lateinit var viewModel: UserViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
viewModel = ViewModelProvider(this)[UserViewModel::class.java]
viewModel.user.observe(this) { user ->
// 更新UI
updateUI(user)
}
viewModel.loadUser(userId)
}
}
// ViewModel:处理UI逻辑
class UserViewModel(
private val getUserUseCase: GetUserUseCase
) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
fun loadUser(userId: String) {
viewModelScope.launch {
try {
val user = getUserUseCase(userId)
_user.value = user
} catch (e: Exception) {
// 处理错误
}
}
}
}
领域层(Domain Layer)
// UseCase:业务逻辑
class GetUserUseCase(
private val repository: UserRepository
) {
suspend operator fun invoke(userId: String): Result<User> {
return try {
val user = repository.getUser(userId)
Result.success(user)
} catch (e: Exception) {
Result.failure(e)
}
}
}
// Entity:领域实体
data class User(
val id: String,
val name: String,
val email: String
)
// Repository接口:定义数据访问接口
interface UserRepository {
suspend fun getUser(userId: String): User
}
数据层(Data Layer)
// Repository实现
class UserRepositoryImpl(
private val remoteDataSource: UserRemoteDataSource,
private val localDataSource: UserLocalDataSource
) : UserRepository {
override suspend fun getUser(userId: String): User {
return try {
// 先尝试从远程获取
val user = remoteDataSource.getUser(userId)
// 保存到本地
localDataSource.saveUser(user)
user
} catch (e: Exception) {
// 如果远程失败,从本地获取
localDataSource.getUser(userId)
}
}
}
// 远程数据源
class UserRemoteDataSource(
private val apiService: ApiService
) {
suspend fun getUser(userId: String): User {
return apiService.getUser(userId).toDomain()
}
}
// 本地数据源
class UserLocalDataSource(
private val userDao: UserDao
) {
suspend fun getUser(userId: String): User {
return userDao.getUser(userId).toDomain()
}
suspend fun saveUser(user: User) {
userDao.insertUser(user.toEntity())
}
}
2. Clean Architecture
依赖规则
表现层 → 领域层 ← 数据层
// 领域层不依赖任何其他层
// Domain Layer
interface UserRepository {
suspend fun getUser(userId: String): User
}
class GetUserUseCase(
private val repository: UserRepository // 依赖接口
) {
suspend operator fun invoke(userId: String): User {
return repository.getUser(userId)
}
}
// 数据层实现领域层的接口
// Data Layer
class UserRepositoryImpl : UserRepository {
override suspend fun getUser(userId: String): User {
// 实现
}
}
// 表现层依赖领域层
// Presentation Layer
class UserViewModel(
private val getUserUseCase: GetUserUseCase // 依赖UseCase
) : ViewModel()
模块化设计
1. 功能模块化
模块结构
app/
├── app/ # 主模块
├── core/ # 核心模块(通用功能)
│ ├── core-common/
│ ├── core-network/
│ └── core-database/
├── feature/ # 功能模块
│ ├── feature-home/
│ ├── feature-user/
│ └── feature-settings/
└── buildSrc/ # 构建脚本
模块依赖关系
// app/build.gradle
dependencies {
implementation project(':core:core-common')
implementation project(':core:core-network')
implementation project(':feature:feature-home')
implementation project(':feature:feature-user')
}
// feature-home/build.gradle
dependencies {
implementation project(':core:core-common')
// feature模块不依赖其他feature模块
}
2. 组件化架构
组件通信
// 使用接口定义组件通信
interface HomeNavigation {
fun navigateToUserDetail(userId: String)
fun navigateToSettings()
}
// Home模块实现
class HomeFragment : Fragment(), HomeNavigation {
override fun navigateToUserDetail(userId: String) {
findNavController().navigate(
HomeFragmentDirections.actionToUserDetail(userId)
)
}
}
// 使用Router进行模块间通信
class AppRouter {
fun navigateToUserDetail(context: Context, userId: String) {
val intent = Intent(context, UserDetailActivity::class.java)
intent.putExtra("user_id", userId)
context.startActivity(intent)
}
}
依赖管理
1. 依赖注入
使用Hilt/Dagger
// 定义Module
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideApiService(): ApiService {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.build()
.create(ApiService::class.java)
}
@Provides
@Singleton
fun provideUserRepository(
apiService: ApiService
): UserRepository {
return UserRepositoryImpl(apiService)
}
}
// 注入依赖
@AndroidEntryPoint
class UserActivity : AppCompatActivity() {
@Inject
lateinit var userRepository: UserRepository
// ...
}
手动依赖注入
// 依赖容器
class AppContainer {
private val apiService: ApiService by lazy {
Retrofit.Builder()
.baseUrl("https://api.example.com/")
.build()
.create(ApiService::class.java)
}
val userRepository: UserRepository by lazy {
UserRepositoryImpl(apiService)
}
}
// 在Application中初始化
class MyApplication : Application() {
val appContainer = AppContainer()
}
// 在Activity中使用
class UserActivity : AppCompatActivity() {
private lateinit var userRepository: UserRepository
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
userRepository = (application as MyApplication)
.appContainer.userRepository
}
}
2. 依赖版本管理
统一版本管理
// buildSrc/src/main/kotlin/Dependencies.kt
object Versions {
const val kotlin = "1.9.0"
const val androidxCore = "1.9.0"
const val androidxAppCompat = "1.6.1"
const val material = "1.8.0"
const val hilt = "2.44"
}
object Dependencies {
const val kotlinStdlib = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}"
const val androidxCoreKtx = "androidx.core:core-ktx:${Versions.androidxCore}"
const val androidxAppCompat = "androidx.appcompat:appcompat:${Versions.androidxAppCompat}"
const val material = "com.google.android.material:material:${Versions.material}"
const val hiltAndroid = "com.google.dagger:hilt-android:${Versions.hilt}"
}
// 在模块中使用
dependencies {
implementation(Dependencies.kotlinStdlib)
implementation(Dependencies.androidxCoreKtx)
implementation(Dependencies.androidxAppCompat)
implementation(Dependencies.material)
}
架构模式选择
1. MVVM模式
MVVM实现
// Model:数据模型
data class User(
val id: String,
val name: String
)
// ViewModel:UI逻辑
class UserViewModel(
private val repository: UserRepository
) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading
fun loadUser(userId: String) {
viewModelScope.launch {
_loading.value = true
try {
val user = repository.getUser(userId)
_user.value = user
} catch (e: Exception) {
// 处理错误
} finally {
_loading.value = false
}
}
}
}
// View:UI
class UserActivity : AppCompatActivity() {
private lateinit var viewModel: UserViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
viewModel = ViewModelProvider(this)[UserViewModel::class.java]
viewModel.user.observe(this) { user ->
// 更新UI
nameTextView.text = user.name
}
viewModel.loading.observe(this) { isLoading ->
progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
}
}
}
2. MVI模式
MVI实现
// State:UI状态
data class UserState(
val user: User? = null,
val isLoading: Boolean = false,
val error: String? = null
)
// Intent:用户意图
sealed class UserIntent {
object LoadUser : UserIntent()
data class RefreshUser(val userId: String) : UserIntent()
}
// ViewModel
class UserViewModel(
private val repository: UserRepository
) : ViewModel() {
private val _state = MutableStateFlow(UserState())
val state: StateFlow<UserState> = _state.asStateFlow()
fun handleIntent(intent: UserIntent) {
when (intent) {
is UserIntent.LoadUser -> loadUser()
is UserIntent.RefreshUser -> refreshUser(intent.userId)
}
}
private fun loadUser() {
viewModelScope.launch {
_state.value = _state.value.copy(isLoading = true)
try {
val user = repository.getUser()
_state.value = _state.value.copy(
user = user,
isLoading = false
)
} catch (e: Exception) {
_state.value = _state.value.copy(
error = e.message,
isLoading = false
)
}
}
}
}
3. Clean Architecture + MVVM
组合使用
// Domain Layer
interface UserRepository {
suspend fun getUser(userId: String): User
}
class GetUserUseCase(
private val repository: UserRepository
) {
suspend operator fun invoke(userId: String): Result<User> {
return try {
Result.success(repository.getUser(userId))
} catch (e: Exception) {
Result.failure(e)
}
}
}
// Presentation Layer (MVVM)
class UserViewModel(
private val getUserUseCase: GetUserUseCase
) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
fun loadUser(userId: String) {
viewModelScope.launch {
when (val result = getUserUseCase(userId)) {
is Result.Success -> _user.value = result.data
is Result.Failure -> {
// 处理错误
}
}
}
}
}
Jetpack架构组件
1. ViewModel
使用ViewModel
class UserViewModel(
private val repository: UserRepository
) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
init {
loadUser()
}
private fun loadUser() {
viewModelScope.launch {
val user = repository.getUser()
_user.value = user
}
}
override fun onCleared() {
super.onCleared()
// 清理资源
}
}
2. LiveData
使用LiveData
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
private val _error = MutableLiveData<String?>()
val error: LiveData<String?> = _error
fun loadUser() {
viewModelScope.launch {
try {
val user = repository.getUser()
_user.value = user
_error.value = null
} catch (e: Exception) {
_error.value = e.message
}
}
}
}
// 在Activity中观察
viewModel.user.observe(this) { user ->
// 更新UI
}
viewModel.error.observe(this) { error ->
error?.let {
// 显示错误
}
}
3. Room数据库
使用Room
// Entity
@Entity(tableName = "users")
data class UserEntity(
@PrimaryKey val id: String,
val name: String,
val email: String
)
// DAO
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :userId")
suspend fun getUser(userId: String): UserEntity?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(user: UserEntity)
@Delete
suspend fun deleteUser(user: UserEntity)
}
// Database
@Database(entities = [UserEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
4. WorkManager
使用WorkManager
// 定义Worker
class SyncWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
// 执行后台任务
syncData()
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
}
// 调度任务
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
WorkManager.getInstance(context).enqueue(syncRequest)
总结
良好的应用架构应该遵循以下原则:
- 关注点分离:每个组件只负责一个职责
- 依赖倒置:依赖接口而非实现
- 分层架构:清晰的分层结构,便于维护和测试
- 模块化设计:功能模块化,提高可复用性
- 依赖管理:使用依赖注入,管理依赖关系
- 架构模式:根据项目需求选择合适的架构模式
- Jetpack组件:充分利用Jetpack架构组件
通过遵循这些最佳实践,可以构建出高质量、可维护、可扩展的Android应用。