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

17 KiB
Raw Blame History

性能优化最佳实践

性能优化是Android应用开发的重要环节直接影响用户体验和应用质量。本文档介绍Android应用性能优化的最佳实践。

目录


性能优化策略

1. 性能优化原则

测量优先

// ✅ 好的做法:先测量,再优化
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")

优化关键路径

// 识别关键路径并优化
class AppInitializer {
    fun initialize() {
        // 关键路径:必须立即初始化
        initCriticalComponents()
        
        // 非关键路径:可以延迟初始化
        Handler(Looper.getMainLooper()).postDelayed({
            initNonCriticalComponents()
        }, 100)
    }
}

2. 性能指标

关键指标

// 启动时间
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优化

延迟初始化

// ✅ 好的做法:延迟初始化非关键组件
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

// 使用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. 首屏优化

减少首屏布局复杂度

<!-- ✅ 好的做法:简化首屏布局 -->
<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延迟加载

<!-- 使用ViewStub延迟加载非关键视图 -->
<ViewStub
    android:id="@+id/viewStub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout="@layout/expensive_view"/>
// 在需要时加载
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

// 使用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. 内存泄漏预防

避免静态引用

// ❌ 不好的做法静态引用Context
object AppContext {
    var context: Context? = null // 可能导致内存泄漏
}

// ✅ 好的做法使用Application Context
object AppContext {
    fun getContext(): Context {
        return MyApplication.instance
    }
}

正确处理生命周期

// ✅ 好的做法:正确处理生命周期
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. 内存使用优化

使用对象池

// 对象池复用对象减少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)

优化图片加载

// 使用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

// build.gradle
dependencies {
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}
// 自动检测内存泄漏
// LeakCanary会自动检测并报告内存泄漏

手动内存分析

// 获取内存信息
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

<!-- ✅ 好的做法使用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. 避免过度绘制

减少背景绘制

<!-- ✅ 好的做法:移除不必要的背景 -->
<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

<!-- 使用clipToPadding减少绘制区域 -->
<RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:padding="16dp"/>

3. RecyclerView优化

ViewHolder复用

// ✅ 好的做法正确实现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

// 使用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. 请求优化

请求合并

// ✅ 好的做法:合并请求
class ApiService {
    @GET("users")
    suspend fun getUsers(@Query("ids") ids: String): List<User>
    // 一次请求获取多个用户,而不是多次请求
}

// ❌ 不好的做法:多次请求
// for (id in userIds) {
//     apiService.getUser(id)
// }

使用缓存

// 使用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

// 服务器端启用Gzip压缩
// 客户端自动处理Gzip响应
// OkHttp自动支持Gzip解压

数据格式优化

// 使用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. 网络监控

监控网络请求

// 使用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

// build.gradle
dependencies {
    implementation 'com.google.firebase:firebase-perf-ktx:20.4.1'
}
// 监控自定义性能指标
val trace = FirebasePerformance.getInstance().newTrace("load_user_data")
trace.start()

// 执行操作
loadUserData()

trace.stop()

自定义性能监控

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

// Android Studio Profiler可以监控
// - CPU使用率
// - 内存使用情况
// - 网络请求
// - 电量消耗

使用Systrace

# 使用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

// Perfetto是更强大的性能分析工具
// 可以分析:
// - CPU调度
// - 内存分配
// - 文件I/O
// - 网络活动

总结

性能优化是一个持续的过程,需要:

  1. 测量优先:先测量性能,找出瓶颈
  2. 优化关键路径:优先优化影响用户体验的关键路径
  3. 启动优化:减少启动时间,提升用户体验
  4. 内存优化:避免内存泄漏,优化内存使用
  5. 布局优化:减少布局层级,避免过度绘制
  6. 网络优化:优化网络请求,使用缓存
  7. 性能监控:持续监控性能指标,及时发现问题

通过遵循这些最佳实践,可以显著提升应用的性能和用户体验。