Files
mkdocs/docs/Google开发文档体系/最佳实践/性能优化最佳实践.md
2026-01-16 14:54:07 +08:00

717 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 性能优化最佳实践
性能优化是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. **性能监控**:持续监控性能指标,及时发现问题
通过遵循这些最佳实践,可以显著提升应用的性能和用户体验。