鏇存柊鏂囨。

This commit is contained in:
renjianbo
2026-01-16 14:54:07 +08:00
parent 2b1834f623
commit 580cd5adb0
10 changed files with 7611 additions and 41 deletions

View File

@@ -13,15 +13,30 @@
"state": {
"type": "markdown",
"state": {
"file": "docs/Obsidian笔记体系/Areas/09-调试与工具链/Systrace_Perfetto全解读.md",
"file": "docs/dify/用户注册及添加成员.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Systrace_Perfetto全解读"
"title": "用户注册及添加成员"
}
},
{
"id": "25c9f7051aac05b3",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "docs/android面试/系统原理/WMS面试.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "WMS面试"
}
}
]
],
"currentTab": 1
}
],
"direction": "vertical"
@@ -174,17 +189,27 @@
},
"left-ribbon": {
"hiddenItems": {
"bases:新建数据库": false,
"switcher:打开快速切换": false,
"graph:查看关系图谱": false,
"canvas:新建白板": false,
"daily-notes:打开/创建今天的日记": false,
"templates:插入模板": false,
"command-palette:打开命令面板": false,
"bases:创建新数据库": false
"command-palette:打开命令面板": false
}
},
"active": "5b497a77c6d68c73",
"active": "25c9f7051aac05b3",
"lastOpenFiles": [
"docs/Obsidian笔记体系/Projects/saars开发/aiapply/未命名 1.md",
"docs/android面试/系统原理/WMS面试.md",
"docs/Obsidian笔记体系/Projects/saars开发/aiapply/未命名.md",
"docs/Obsidian笔记体系/Projects/saars开发/aiapply",
"docs/dify/管理员账户.md",
"docs/dify/用户注册及添加成员.md",
"docs/dify/密码输入错误次数超过限制时的机制.md",
"docs/dify/使用dify可以生成一个专项事务助手吗比如公司正规化事务助手.md",
"docs/dify/作为安卓高级开发工程师,除了项目管理,你完全可以在技术专项、团队效能和个人成长三大领域构建更懂你的专属助手.md",
"docs/Obsidian笔记体系/Areas/09-调试与工具链/Systrace_Perfetto全解读.md",
"docs/技术面试问题回答.md",
"docs/Google开发文档体系/视频和教程/技术会议.md",
"docs/Google开发文档体系/视频和教程/官方视频教程.md",
@@ -202,15 +227,6 @@
"docs/Google开发文档体系/示例代码/架构示例.md",
"docs/Google开发文档体系/示例代码/官方示例项目.md",
"docs/Google开发文档体系/示例代码/代码片段.md",
"docs/Google开发文档体系/最佳实践/用户体验最佳实践.md",
"docs/Google开发文档体系/最佳实践/应用架构最佳实践.md",
"docs/Google开发文档体系/最佳实践/性能优化最佳实践.md",
"docs/Google开发文档体系/最佳实践/安全最佳实践.md",
"docs/Google开发文档体系/最佳实践/代码质量最佳实践.md",
"docs/Google开发文档体系/工具和资源/调试工具.md",
"docs/Google开发文档体系/工具和资源/构建系统.md",
"docs/Google开发文档体系/工具和资源/Android_Studio.md",
"docs/Google开发文档体系/工具和资源/性能分析工具.md",
"docs/Google开发文档体系/视频和教程",
"docs/Google开发文档体系/核心主题",
"docs/Google开发文档体系/示例代码",
@@ -219,7 +235,6 @@
"docs/Google开发文档体系/入门指南",
"docs/Google开发文档体系/API参考",
"docs/Google开发文档体系",
"docs/android面试/技术面试问题回答.txt",
"技术面试问题回答.txt"
"docs/android面试/技术面试问题回答.txt"
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,786 @@
# 应用架构最佳实践
## 待补充内容
良好的应用架构是Android应用开发的基础它直接影响应用的可维护性、可测试性和可扩展性。本文档介绍Android应用架构设计的最佳实践。
- 架构设计原则
- 分层架构
- 模块化设计
- 依赖管理
- 架构模式选择
## 目录
- [架构设计原则](#架构设计原则)
- [分层架构](#分层架构)
- [模块化设计](#模块化设计)
- [依赖管理](#依赖管理)
- [架构模式选择](#架构模式选择)
- [Jetpack架构组件](#jetpack架构组件)
---
## 架构设计原则
### 1. 关注点分离Separation of Concerns
#### 单一职责原则
```kotlin
// ✅ 好的设计:每个类只有一个职责
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
#### 依赖接口而非实现
```kotlin
// ✅ 好的设计:依赖接口
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
#### 对扩展开放,对修改关闭
```kotlin
// ✅ 好的设计:通过扩展添加功能
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
#### 使用小而专的接口
```kotlin
// ✅ 好的设计:小而专的接口
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
```kotlin
// 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
```kotlin
// 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
```kotlin
// 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
#### 依赖规则
```
表现层 → 领域层 ← 数据层
```
```kotlin
// 领域层不依赖任何其他层
// 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/ # 构建脚本
```
#### 模块依赖关系
```gradle
// 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. 组件化架构
#### 组件通信
```kotlin
// 使用接口定义组件通信
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
```kotlin
// 定义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
// ...
}
```
#### 手动依赖注入
```kotlin
// 依赖容器
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. 依赖版本管理
#### 统一版本管理
```gradle
// 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实现
```kotlin
// Model数据模型
data class User(
val id: String,
val name: String
)
// ViewModelUI逻辑
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
}
}
}
}
// ViewUI
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实现
```kotlin
// StateUI状态
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
#### 组合使用
```kotlin
// 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
```kotlin
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
```kotlin
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
```kotlin
// 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
```kotlin
// 定义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)
```
---
## 总结
良好的应用架构应该遵循以下原则:
1. **关注点分离**:每个组件只负责一个职责
2. **依赖倒置**:依赖接口而非实现
3. **分层架构**:清晰的分层结构,便于维护和测试
4. **模块化设计**:功能模块化,提高可复用性
5. **依赖管理**:使用依赖注入,管理依赖关系
6. **架构模式**:根据项目需求选择合适的架构模式
7. **Jetpack组件**充分利用Jetpack架构组件
通过遵循这些最佳实践可以构建出高质量、可维护、可扩展的Android应用。

View File

@@ -1,10 +1,716 @@
# 性能优化最佳实践
## 待补充内容
性能优化是Android应用开发的重要环节直接影响用户体验和应用质量。本文档介绍Android应用性能优化的最佳实践。
- 性能优化策略
- 启动优化实践
- 内存优化实践
- 布局优化实践
- 网络优化实践
- 性能监控
## 目录
- [性能优化策略](#性能优化策略)
- [启动优化实践](#启动优化实践)
- [内存优化实践](#内存优化实践)
- [布局优化实践](#布局优化实践)
- [网络优化实践](#网络优化实践)
- [性能监控](#性能监控)
---
## 性能优化策略
### 1. 性能优化原则
#### 测量优先
```kotlin
// ✅ 好的做法:先测量,再优化
class PerformanceMonitor {
fun measureTime(block: () -> Unit): Long {
val startTime = System.currentTimeMillis()
block()
return System.currentTimeMillis() - startTime
}
fun measureMemory(block: () -> Unit): Long {
val runtime = Runtime.getRuntime()
val beforeMemory = runtime.totalMemory() - runtime.freeMemory()
block()
val afterMemory = runtime.totalMemory() - runtime.freeMemory()
return afterMemory - beforeMemory
}
}
// 使用
val monitor = PerformanceMonitor()
val time = monitor.measureTime {
// 执行代码
}
Log.d("Performance", "执行时间: ${time}ms")
```
#### 优化关键路径
```kotlin
// 识别关键路径并优化
class AppInitializer {
fun initialize() {
// 关键路径:必须立即初始化
initCriticalComponents()
// 非关键路径:可以延迟初始化
Handler(Looper.getMainLooper()).postDelayed({
initNonCriticalComponents()
}, 100)
}
}
```
### 2. 性能指标
#### 关键指标
```kotlin
// 启动时间
class StartupTimeTracker {
private var appStartTime: Long = 0
fun onAppStart() {
appStartTime = System.currentTimeMillis()
}
fun onFirstFrame() {
val startupTime = System.currentTimeMillis() - appStartTime
Log.d("Performance", "启动时间: ${startupTime}ms")
}
}
// 内存使用
class MemoryTracker {
fun getMemoryUsage(): MemoryInfo {
val runtime = Runtime.getRuntime()
val totalMemory = runtime.totalMemory()
val freeMemory = runtime.freeMemory()
val usedMemory = totalMemory - freeMemory
return MemoryInfo(
total = totalMemory,
used = usedMemory,
free = freeMemory
)
}
}
```
---
## 启动优化实践
### 1. Application优化
#### 延迟初始化
```kotlin
// ✅ 好的做法:延迟初始化非关键组件
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 关键初始化:必须立即执行
initCriticalComponents()
// 非关键初始化:延迟执行
initNonCriticalComponentsAsync()
}
private fun initCriticalComponents() {
// 初始化关键组件
CrashReporting.init(this)
}
private fun initNonCriticalComponentsAsync() {
// 使用后台线程初始化
Thread {
// 初始化非关键组件
Analytics.init(this)
ImageLoader.init(this)
}.start()
}
}
```
#### 使用App Startup
```kotlin
// 使用App Startup统一管理初始化
class MyInitializer : Initializer<Unit> {
override fun create(context: Context) {
// 初始化组件
Analytics.init(context)
}
override fun dependencies(): List<Class<out Initializer<*>>> {
// 定义依赖关系
return listOf(OtherInitializer::class.java)
}
}
// 在AndroidManifest.xml中注册
// <provider
// android:name="androidx.startup.InitializationProvider"
// android:authorities="${applicationId}.androidx-startup"
// android:exported="false"
// tools:node="merge">
// <meta-data
// android:name="com.example.MyInitializer"
// android:value="androidx.startup" />
// </provider>
```
### 2. 首屏优化
#### 减少首屏布局复杂度
```xml
<!-- ✅ 好的做法:简化首屏布局 -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 只显示关键内容 -->
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="欢迎"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- ❌ 不好的做法:首屏包含过多内容 -->
```
#### 使用ViewStub延迟加载
```xml
<!-- 使用ViewStub延迟加载非关键视图 -->
<ViewStub
android:id="@+id/viewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/expensive_view"/>
```
```kotlin
// 在需要时加载
class MainActivity : AppCompatActivity() {
private lateinit var viewStub: ViewStub
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewStub = findViewById(R.id.viewStub)
// 延迟加载
button.setOnClickListener {
if (viewStub.parent != null) {
viewStub.inflate()
}
}
}
}
```
### 3. 启动时间测量
#### 使用Trace API
```kotlin
// 使用Trace API标记启动流程
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Trace.beginSection("MainActivity.onCreate")
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Trace.beginSection("initViews")
initViews()
Trace.endSection()
Trace.beginSection("loadData")
loadData()
Trace.endSection()
Trace.endSection()
}
}
// 使用Systrace分析
// python systrace.py -t 10 -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res
```
---
## 内存优化实践
### 1. 内存泄漏预防
#### 避免静态引用
```kotlin
// ❌ 不好的做法静态引用Context
object AppContext {
var context: Context? = null // 可能导致内存泄漏
}
// ✅ 好的做法使用Application Context
object AppContext {
fun getContext(): Context {
return MyApplication.instance
}
}
```
#### 正确处理生命周期
```kotlin
// ✅ 好的做法:正确处理生命周期
class MainActivity : AppCompatActivity() {
private var handler: Handler? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 使用静态内部类+WeakReference
handler = MyHandler(this)
}
override fun onDestroy() {
super.onDestroy()
handler?.removeCallbacksAndMessages(null)
handler = null
}
private class MyHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) {
private val activityRef = WeakReference(activity)
override fun handleMessage(msg: Message) {
activityRef.get()?.let {
// 处理消息
}
}
}
}
```
### 2. 内存使用优化
#### 使用对象池
```kotlin
// 对象池复用对象减少GC
class ObjectPool<T>(private val factory: () -> T, private val maxSize: Int = 10) {
private val pool = mutableListOf<T>()
fun acquire(): T {
return if (pool.isNotEmpty()) {
pool.removeAt(pool.size - 1)
} else {
factory()
}
}
fun release(obj: T) {
if (pool.size < maxSize) {
pool.add(obj)
}
}
}
// 使用
val viewPool = ObjectPool({ View(context) })
val view = viewPool.acquire()
// 使用view
viewPool.release(view)
```
#### 优化图片加载
```kotlin
// 使用Glide等图片加载库
Glide.with(context)
.load(imageUrl)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.override(800, 600) // 指定尺寸
.into(imageView)
// 使用WebP格式
// WebP格式比PNG/JPG更小加载更快
// 使用图片压缩
fun compressBitmap(bitmap: Bitmap, quality: Int = 80): ByteArray {
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.WEBP, quality, stream)
return stream.toByteArray()
}
```
### 3. 内存监控
#### 使用LeakCanary
```gradle
// build.gradle
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}
```
```kotlin
// 自动检测内存泄漏
// LeakCanary会自动检测并报告内存泄漏
```
#### 手动内存分析
```kotlin
// 获取内存信息
class MemoryAnalyzer {
fun getMemoryInfo(): String {
val runtime = Runtime.getRuntime()
val maxMemory = runtime.maxMemory()
val totalMemory = runtime.totalMemory()
val freeMemory = runtime.freeMemory()
val usedMemory = totalMemory - freeMemory
return """
Max Memory: ${maxMemory / 1024 / 1024}MB
Total Memory: ${totalMemory / 1024 / 1024}MB
Used Memory: ${usedMemory / 1024 / 1024}MB
Free Memory: ${freeMemory / 1024 / 1024}MB
""".trimIndent()
}
fun dumpHeap(): File {
val heapDumpFile = File(cacheDir, "heap_dump.hprof")
Debug.dumpHprofData(heapDumpFile.absolutePath)
return heapDumpFile
}
}
```
---
## 布局优化实践
### 1. 减少布局层级
#### 使用ConstraintLayout
```xml
<!-- ✅ 好的做法使用ConstraintLayout减少层级 -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="副标题"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- ❌ 不好的做法:嵌套过多 -->
<LinearLayout>
<LinearLayout>
<TextView/>
</LinearLayout>
</LinearLayout>
```
### 2. 避免过度绘制
#### 减少背景绘制
```xml
<!-- ✅ 好的做法:移除不必要的背景 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white">
<!-- 子视图不需要再设置背景 -->
</LinearLayout>
<!-- ❌ 不好的做法:多层背景 -->
<LinearLayout android:background="@color/background1">
<LinearLayout android:background="@color/background2">
<!-- 导致过度绘制 -->
</LinearLayout>
</LinearLayout>
```
#### 使用clipToPadding
```xml
<!-- 使用clipToPadding减少绘制区域 -->
<RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="16dp"/>
```
### 3. RecyclerView优化
#### ViewHolder复用
```kotlin
// ✅ 好的做法正确实现ViewHolder
class UserAdapter : RecyclerView.Adapter<UserAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val nameTextView: TextView = itemView.findViewById(R.id.name)
val emailTextView: TextView = itemView.findViewById(R.id.email)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_user, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val user = users[position]
holder.nameTextView.text = user.name
holder.emailTextView.text = user.email
}
}
```
#### 使用DiffUtil
```kotlin
// 使用DiffUtil优化列表更新
class UserDiffCallback(
private val oldList: List<User>,
private val newList: List<User>
) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].id == newList[newItemPosition].id
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
// 使用
val diffResult = DiffUtil.calculateDiff(UserDiffCallback(oldList, newList))
adapter.users = newList
diffResult.dispatchUpdatesTo(adapter)
```
---
## 网络优化实践
### 1. 请求优化
#### 请求合并
```kotlin
// ✅ 好的做法:合并请求
class ApiService {
@GET("users")
suspend fun getUsers(@Query("ids") ids: String): List<User>
// 一次请求获取多个用户,而不是多次请求
}
// ❌ 不好的做法:多次请求
// for (id in userIds) {
// apiService.getUser(id)
// }
```
#### 使用缓存
```kotlin
// 使用OkHttp缓存
val client = OkHttpClient.Builder()
.cache(Cache(cacheDir, 10 * 1024 * 1024)) // 10MB缓存
.build()
// 使用Retrofit缓存
@Headers("Cache-Control: max-age=3600")
@GET("users/{id}")
suspend fun getUser(@Path("id") id: String): User
```
### 2. 数据压缩
#### 使用Gzip
```kotlin
// 服务器端启用Gzip压缩
// 客户端自动处理Gzip响应
// OkHttp自动支持Gzip解压
```
#### 数据格式优化
```kotlin
// 使用Protobuf替代JSON
// Protobuf更小、更快
data class User(
val id: String,
val name: String,
val email: String
)
// 转换为Protobuf
val userProto = UserProto.newBuilder()
.setId(user.id)
.setName(user.name)
.setEmail(user.email)
.build()
```
### 3. 网络监控
#### 监控网络请求
```kotlin
// 使用OkHttp Interceptor监控
class NetworkMonitorInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val startTime = System.currentTimeMillis()
val response = chain.proceed(request)
val duration = System.currentTimeMillis() - startTime
Log.d("Network", "${request.url} - ${duration}ms")
return response
}
}
val client = OkHttpClient.Builder()
.addInterceptor(NetworkMonitorInterceptor())
.build()
```
---
## 性能监控
### 1. 性能指标收集
#### 使用Firebase Performance
```gradle
// build.gradle
dependencies {
implementation 'com.google.firebase:firebase-perf-ktx:20.4.1'
}
```
```kotlin
// 监控自定义性能指标
val trace = FirebasePerformance.getInstance().newTrace("load_user_data")
trace.start()
// 执行操作
loadUserData()
trace.stop()
```
#### 自定义性能监控
```kotlin
class PerformanceTracker {
private val metrics = mutableMapOf<String, Long>()
fun startTrace(name: String) {
metrics[name] = System.currentTimeMillis()
}
fun endTrace(name: String) {
val startTime = metrics[name]
if (startTime != null) {
val duration = System.currentTimeMillis() - startTime
Log.d("Performance", "$name: ${duration}ms")
metrics.remove(name)
}
}
}
// 使用
val tracker = PerformanceTracker()
tracker.startTrace("load_data")
// 执行操作
tracker.endTrace("load_data")
```
### 2. 性能分析工具
#### 使用Android Profiler
```kotlin
// Android Studio Profiler可以监控
// - CPU使用率
// - 内存使用情况
// - 网络请求
// - 电量消耗
```
#### 使用Systrace
```bash
# 使用Systrace分析性能
python systrace.py -t 10 -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res
# 在代码中标记
Trace.beginSection("my_section")
// 执行代码
Trace.endSection()
```
#### 使用Perfetto
```kotlin
// Perfetto是更强大的性能分析工具
// 可以分析:
// - CPU调度
// - 内存分配
// - 文件I/O
// - 网络活动
```
---
## 总结
性能优化是一个持续的过程,需要:
1. **测量优先**:先测量性能,找出瓶颈
2. **优化关键路径**:优先优化影响用户体验的关键路径
3. **启动优化**:减少启动时间,提升用户体验
4. **内存优化**:避免内存泄漏,优化内存使用
5. **布局优化**:减少布局层级,避免过度绘制
6. **网络优化**:优化网络请求,使用缓存
7. **性能监控**:持续监控性能指标,及时发现问题
通过遵循这些最佳实践,可以显著提升应用的性能和用户体验。

View File

@@ -1,9 +1,789 @@
# 用户体验最佳实践
## 待补充内容
用户体验UX是Android应用成功的关键因素。良好的用户体验能够提升用户满意度、增加用户留存率并提升应用在应用商店的评分。本文档介绍Android应用开发中的用户体验最佳实践。
- UX设计原则
- 界面设计
- 交互设计
- 可访问性
- 国际化
## 目录
- [UX设计原则](#ux设计原则)
- [界面设计](#界面设计)
- [交互设计](#交互设计)
- [可访问性](#可访问性)
- [国际化](#国际化)
- [性能与体验](#性能与体验)
---
## UX设计原则
### 1. 以用户为中心
#### 理解用户需求
```kotlin
// 在设计功能前,先理解用户需求
// 1. 用户画像分析
// 2. 用户场景分析
// 3. 用户痛点识别
// 示例:电商应用
// 用户需求:快速找到商品并完成购买
// 设计要点:
// - 搜索功能突出
// - 商品信息清晰
// - 购买流程简化
```
#### 用户反馈机制
```kotlin
// 建立用户反馈渠道
class FeedbackManager {
fun collectUserFeedback(feedback: String) {
// 收集用户反馈
Analytics.logEvent("user_feedback", mapOf("content" to feedback))
}
fun showFeedbackDialog(context: Context) {
// 显示反馈对话框
MaterialAlertDialogBuilder(context)
.setTitle("反馈建议")
.setView(EditText(context))
.setPositiveButton("提交") { _, _ ->
collectUserFeedback()
}
.show()
}
}
```
### 2. 简洁性原则
#### 界面简洁
```xml
<!-- ✅ 好的设计:简洁清晰 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题"
android:textSize="18sp"
android:textStyle="bold"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="描述信息"
android:textSize="14sp"/>
</LinearLayout>
<!-- ❌ 不好的设计:信息过载 -->
<!-- 避免在一个界面显示过多信息 -->
```
#### 操作简化
```kotlin
// ✅ 好的设计:简化操作流程
class CheckoutActivity : AppCompatActivity() {
fun proceedToPayment() {
// 一键支付,减少步骤
if (validateOrder()) {
startActivity(Intent(this, PaymentActivity::class.java))
}
}
}
// ❌ 不好的设计:操作步骤过多
// 避免让用户进行过多步骤才能完成操作
```
### 3. 一致性原则
#### 视觉一致性
```kotlin
// 使用统一的主题和样式
// styles.xml
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryVariant">@color/primary_variant</item>
<item name="colorSecondary">@color/secondary</item>
<item name="textAppearanceHeadline1">@style/TextAppearance.Headline1</item>
<item name="textAppearanceBody1">@style/TextAppearance.Body1</item>
</style>
```
#### 交互一致性
```kotlin
// 统一的交互模式
class NavigationHelper {
companion object {
// 统一的导航方式
fun navigateToDetail(context: Context, itemId: String) {
val intent = Intent(context, DetailActivity::class.java)
intent.putExtra("item_id", itemId)
context.startActivity(intent)
}
// 统一的返回方式
fun handleBackPress(activity: Activity): Boolean {
if (activity.supportFragmentManager.backStackEntryCount > 0) {
activity.supportFragmentManager.popBackStack()
return true
}
return false
}
}
}
```
### 4. 反馈原则
#### 操作反馈
```kotlin
// 用户操作后提供即时反馈
class UserFeedbackHelper {
fun showLoading(context: Context) {
// 显示加载状态
ProgressDialog.show(context, "加载中", "请稍候...")
}
fun showSuccess(context: Context, message: String) {
// 显示成功提示
Snackbar.make(
findViewById(android.R.id.content),
message,
Snackbar.LENGTH_SHORT
).show()
}
fun showError(context: Context, message: String) {
// 显示错误提示
MaterialAlertDialogBuilder(context)
.setTitle("错误")
.setMessage(message)
.setPositiveButton("确定", null)
.show()
}
}
```
#### 状态反馈
```kotlin
// 使用状态指示器
class StatusIndicator {
fun showStatus(view: View, status: Status) {
when (status) {
Status.LOADING -> {
view.alpha = 0.5f
view.isEnabled = false
}
Status.SUCCESS -> {
view.alpha = 1.0f
view.isEnabled = true
}
Status.ERROR -> {
view.alpha = 0.5f
view.isEnabled = false
}
}
}
}
```
---
## 界面设计
### 1. Material Design
#### Material Design组件
```xml
<!-- 使用Material Design组件 -->
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="描述"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
```
#### Material主题
```xml
<!-- themes.xml -->
<resources>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- 主色调 -->
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryVariant">@color/primary_variant</item>
<item name="colorOnPrimary">@color/on_primary</item>
<!-- 次要色调 -->
<item name="colorSecondary">@color/secondary</item>
<item name="colorSecondaryVariant">@color/secondary_variant</item>
<item name="colorOnSecondary">@color/on_secondary</item>
<!-- 背景色 -->
<item name="android:colorBackground">@color/background</item>
<item name="colorSurface">@color/surface</item>
<!-- 错误色 -->
<item name="colorError">@color/error</item>
<item name="colorOnError">@color/on_error</item>
</style>
</resources>
```
### 2. 响应式设计
#### 多屏幕适配
```xml
<!-- 使用ConstraintLayout实现响应式布局 -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="标题"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="16dp"/>
<RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
```
#### 横竖屏适配
```kotlin
// 横竖屏布局适配
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 根据屏幕方向加载不同布局
val layoutRes = if (isLandscape()) {
R.layout.activity_main_landscape
} else {
R.layout.activity_main_portrait
}
setContentView(layoutRes)
}
private fun isLandscape(): Boolean {
return resources.configuration.orientation ==
Configuration.ORIENTATION_LANDSCAPE
}
}
```
### 3. 布局优化
#### 减少布局层级
```xml
<!-- ❌ 不好的设计:嵌套过多 -->
<LinearLayout>
<LinearLayout>
<LinearLayout>
<TextView/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- ✅ 好的设计使用ConstraintLayout减少层级 -->
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
```
#### 使用ViewStub延迟加载
```xml
<!-- 使用ViewStub延迟加载非关键视图 -->
<ViewStub
android:id="@+id/viewStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/expensive_view"/>
```
```kotlin
// 在需要时加载ViewStub
class MainActivity : AppCompatActivity() {
private lateinit var viewStub: ViewStub
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewStub = findViewById(R.id.viewStub)
// 延迟加载
button.setOnClickListener {
if (viewStub.parent != null) {
viewStub.inflate()
}
}
}
}
```
---
## 交互设计
### 1. 导航设计
#### 底部导航
```xml
<!-- 使用BottomNavigationView -->
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_navigation"
app:itemIconTint="@color/bottom_nav_color"
app:itemTextColor="@color/bottom_nav_color"/>
```
```kotlin
// 处理底部导航点击
bottomNavigation.setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.nav_home -> {
// 导航到首页
navigateToHome()
true
}
R.id.nav_search -> {
// 导航到搜索
navigateToSearch()
true
}
R.id.nav_profile -> {
// 导航到个人中心
navigateToProfile()
true
}
else -> false
}
}
```
#### 导航组件
```kotlin
// 使用Navigation Component
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
// 设置导航监听
navController.addOnDestinationChangedListener { _, destination, _ ->
// 根据目标更新UI
updateUI(destination.id)
}
}
}
```
### 2. 手势交互
#### 滑动操作
```kotlin
// 实现滑动删除
class SwipeToDeleteCallback(
private val adapter: RecyclerView.Adapter<*>
) : ItemTouchHelper.SimpleCallback(
0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val position = viewHolder.adapterPosition
// 删除项
adapter.notifyItemRemoved(position)
}
}
// 使用
val itemTouchHelper = ItemTouchHelper(SwipeToDeleteCallback(adapter))
itemTouchHelper.attachToRecyclerView(recyclerView)
```
#### 点击反馈
```kotlin
// 使用Ripple效果提供点击反馈
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"/>
```
### 3. 动画设计
#### 过渡动画
```kotlin
// Activity过渡动画
class DetailActivity : AppCompatActivity() {
companion object {
fun start(context: Context, item: Item, imageView: ImageView) {
val intent = Intent(context, DetailActivity::class.java)
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
context as Activity,
imageView,
"item_image"
)
context.startActivity(intent, options.toBundle())
}
}
}
```
```xml
<!-- 在DetailActivity中设置共享元素 -->
<ImageView
android:id="@+id/itemImage"
android:transitionName="item_image"
android:layout_width="match_parent"
android:layout_height="200dp"/>
```
#### 微交互动画
```kotlin
// 使用属性动画
fun animateButtonClick(button: View) {
button.animate()
.scaleX(0.9f)
.scaleY(0.9f)
.setDuration(100)
.withEndAction {
button.animate()
.scaleX(1.0f)
.scaleY(1.0f)
.setDuration(100)
.start()
}
.start()
}
```
---
## 可访问性
### 1. 内容标签
#### 添加内容描述
```xml
<!-- 为视图添加内容描述 -->
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/icon_description"/>
<Button
android:id="@+id/submitButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/submit"
android:contentDescription="@string/submit_button_description"/>
```
```kotlin
// 动态设置内容描述
imageView.contentDescription = getString(R.string.icon_description)
button.contentDescription = getString(R.string.submit_button_description)
```
### 2. 触摸目标大小
#### 最小触摸区域
```xml
<!-- 确保触摸目标至少48dp x 48dp -->
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48dp"
android:minHeight="48dp"
android:padding="12dp"/>
```
### 3. 文字大小
#### 支持文字缩放
```xml
<!-- 使用sp单位支持系统文字缩放 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"/>
<!-- 避免使用dp单位设置文字大小 -->
<!-- ❌ android:textSize="16dp" -->
```
### 4. 颜色对比度
#### 确保足够的对比度
```kotlin
// 检查颜色对比度
fun checkContrastRatio(foreground: Int, background: Int): Boolean {
val foregroundLuminance = calculateLuminance(foreground)
val backgroundLuminance = calculateLuminance(background)
val contrastRatio = if (foregroundLuminance > backgroundLuminance) {
(foregroundLuminance + 0.05) / (backgroundLuminance + 0.05)
} else {
(backgroundLuminance + 0.05) / (foregroundLuminance + 0.05)
}
// WCAG AA标准文字至少4.5:1大文字至少3:1
return contrastRatio >= 4.5
}
```
---
## 国际化
### 1. 字符串资源
#### 外部化字符串
```xml
<!-- strings.xml (默认) -->
<resources>
<string name="welcome_message">Welcome</string>
<string name="button_submit">Submit</string>
</resources>
<!-- values-zh/strings.xml (中文) -->
<resources>
<string name="welcome_message">欢迎</string>
<string name="button_submit">提交</string>
</resources>
<!-- values-es/strings.xml (西班牙语) -->
<resources>
<string name="welcome_message">Bienvenido</string>
<string name="button_submit">Enviar</string>
</resources>
```
```kotlin
// 使用字符串资源
textView.text = getString(R.string.welcome_message)
// 带参数的字符串
// strings.xml
<string name="welcome_user">Welcome, %1$s!</string>
textView.text = getString(R.string.welcome_user, userName)
```
### 2. 布局适配
#### RTL支持
```xml
<!-- 使用start/end替代left/right -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:gravity="start"/>
<!-- ❌ 避免使用left/right -->
<!-- android:layout_marginLeft="16dp" -->
```
```kotlin
// 在代码中使用start/end
view.setPaddingRelative(
paddingStart,
paddingTop,
paddingEnd,
paddingBottom
)
```
### 3. 日期和数字格式
#### 本地化格式
```kotlin
// 使用本地化的日期格式
fun formatDate(date: Date, locale: Locale): String {
val dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale)
return dateFormat.format(date)
}
// 使用本地化的数字格式
fun formatNumber(number: Number, locale: Locale): String {
val numberFormat = NumberFormat.getNumberInstance(locale)
return numberFormat.format(number)
}
// 使用本地化的货币格式
fun formatCurrency(amount: Double, locale: Locale): String {
val currencyFormat = NumberFormat.getCurrencyInstance(locale)
return currencyFormat.format(amount)
}
```
---
## 性能与体验
### 1. 启动优化
#### 减少启动时间
```kotlin
// 延迟初始化非关键组件
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 关键初始化
initCriticalComponents()
// 延迟初始化非关键组件
Handler(Looper.getMainLooper()).postDelayed({
initNonCriticalComponents()
}, 100)
}
}
```
### 2. 流畅度优化
#### 避免主线程阻塞
```kotlin
// 使用协程处理耗时操作
class MainActivity : AppCompatActivity() {
private val viewModelScope = ViewModelScope()
fun loadData() {
viewModelScope.launch {
// 在后台线程执行
val data = withContext(Dispatchers.IO) {
repository.loadData()
}
// 在主线程更新UI
withContext(Dispatchers.Main) {
updateUI(data)
}
}
}
}
```
### 3. 加载状态
#### 优雅的加载体验
```kotlin
// 使用Skeleton Screen
class SkeletonHelper {
fun showSkeleton(view: View) {
val skeleton = SkeletonScreen.Builder()
.load(R.layout.skeleton_layout)
.color(R.color.skeleton_color)
.angle(0)
.duration(1000)
.show()
}
}
```
---
## 总结
良好的用户体验需要从多个方面考虑:
1. **设计原则**:以用户为中心,保持简洁和一致
2. **界面设计**遵循Material Design支持多屏幕适配
3. **交互设计**:提供清晰的导航和流畅的交互
4. **可访问性**:确保所有用户都能使用应用
5. **国际化**:支持多语言和不同地区的用户
6. **性能优化**:确保应用流畅运行,提供良好的体验
通过遵循这些最佳实践可以创建出用户喜爱的高质量Android应用。

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,183 @@
项目低代码智能体功能扩展
该项目可扩展低代码快速搭建智能体的功能吗
检查项目结构,评估是否可扩展低代码快速搭建智能体的功能。
继续查看项目架构,评估是否可扩展低代码智能体搭建功能。
查看 API 路由和核心组件,评估扩展能力:
基于对项目的分析,评估如下:
## 项目扩展低代码智能体搭建的可行性评估
### 当前项目优势
1. 模板系统
- 结构化模板(角色、任务、上下文、约束)
- 变量系统(文本、选择、数字、布尔等)
- 模板管理和分享
1. 多模型支持
- 支持 OpenAI、Anthropic、DeepSeek
- 单模型和批量测试
1. 部署能力
- 代码生成Python、JavaScript、TypeScript
- 多框架支持FastAPI、Express 
1. 用户系统
- 认证、权限、模板归属
### 需要扩展的核心功能
文档中提到了“提示词链”概念,但尚未实现。要支持低代码智能体搭建,需要添加:
#### 1. 工作流编排系统
- 将多个模板串联成工作流
- 节点连接(顺序、并行、条件分支)
- 数据流转(上一步输出作为下一步输入)
#### 2. 可视化工作流编辑器
- 拖拽式节点编辑器
- 节点类型:模板节点、条件节点、工具节点、数据节点
- 连线表示数据流
#### 3. 智能体运行时引擎
- 工作流执行引擎
- 状态管理(持久化、恢复)
- 错误处理和重试
#### 4. 工具集成能力
- 外部 API 调用
- 数据库操作
- 文件处理
- 定时任务
#### 5. 触发器系统
- Webhook 触发
- 定时触发
- 事件触发
- 手动触发
### 实现建议
基于现有架构,建议按以下步骤扩展:
#### 阶段一:工作流基础(核心)
1. 数据库扩展:添加工作流表、节点表、连接表
2. 工作流 API创建、执行、管理
3. 简单执行引擎:顺序执行多个模板
#### 阶段二:可视化编辑器
1. 使用 React Flow 或类似库
2. 节点组件:模板节点、条件节点
3. 连线与数据映射
#### 阶段三:高级功能
1. 条件分支与循环
2. 工具集成API、数据库
3. 触发器系统
### 技术实现路径
// 1. 扩展数据库模型Prisma Schema
model Workflow {
  id          String   @id @default(cuid())
  name        String
  description String?
  nodes       WorkflowNode[]
  edges       WorkflowEdge[]
  authorId    String
  // ...
}
model WorkflowNode {
  id         String   @id @default(cuid())
  workflowId String
  type       String   // 'template' | 'condition' | 'tool' | 'data'
  templateId String?  // 如果是模板节点
  config     String   // JSON 配置
  // ...
}
// 2. 工作流执行引擎
class WorkflowEngine {
  async execute(workflowId: string, input: any) {
    // 执行工作流逻辑
  }
}
### 结论
- 可行性:高。项目具备良好基础,架构清晰,易于扩展。
- 工作量:中等。核心工作流功能约 2-3 周完整低代码平台约 2-3 个月。
- 建议:先实现工作流编排和执行引擎,再逐步添加可视化编辑器和高级功能。
需要我帮你开始实现工作流系统吗?我可以:
1. 设计数据库模型
2. 创建工作流 API
3. 实现基础执行引擎
4. 构建可视化编辑器界面

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -185,6 +185,8 @@ nav:
- Obsidian笔记体系/Projects/知你-调测/知你--调测.md
- Obsidian笔记体系/Daily/2026-01-14.md
- Obsidian笔记体系/Daily/2026-01-15.md
- Obsidian笔记体系/Projects/saars开发/aiapply/未命名 1.md
- Obsidian笔记体系/Projects/saars开发/aiapply/未命名.md
- gerrit:
- gerrit/gerrit上传代码详细指南.md
- gerrit/gerrit分支规范.md
@@ -199,6 +201,7 @@ nav:
- dify/使用dify可以生成一个专项事务助手吗比如公司正规化事务助手.md
- dify/密码输入错误次数超过限制时的机制.md
- dify/管理员账户.md
- dify/用户注册及添加成员.md
- git:
- git/Git add . 后如何撤销.md
- git/git同步远程分支总结.md
@@ -285,6 +288,7 @@ nav:
- android面试/项目经验/问题排查经验.md
- android面试/项目经验/项目架构设计.md
- android面试/技术面试问题回答.md
- android面试/系统原理/WMS面试.md
- Google开发文档体系:
- Google开发文档体系/API参考/Android_API概览.md
- Google开发文档体系/API参考/Jetpack_API.md