第七章:安卓性能优化

本章涵盖 Android App 全维度性能优化:帧率优化与 Jank 检测、内存泄漏分析、冷启动优化与 Baseline Profiles、包体积减小、电量优化,以及 Compose 专项性能调优。


📋 章节目录

主题
7.1 帧率优化(16ms 原则 / Jank 检测 / Systrace)
7.2 内存优化(内存泄漏 / LeakCanary / MAT)
7.3 启动优化(冷启动 / Baseline Profiles)
7.4 包体积优化(R8 / ABI Split / Bundle)
7.5 电量与网络优化
7.6 Compose 性能调优

7.1 帧率优化

16ms 原则与丢帧检测

复制代码
屏幕刷新率 60Hz → 每帧预算 = 1000ms / 60 = 16.67ms
屏幕刷新率 120Hz → 每帧预算 = 1000ms / 120 = 8.33ms

帧渲染两阶段:
  Main Thread(UI Thread):测量、布局、Record DisplayList
  RenderThread(硬件加速):执行 DisplayList,提交 GPU

Jank(丢帧)= 某帧用时超过预算,导致跳帧/卡顿
kotlin 复制代码
// 检测主线程卡顿:BlockCanary / 自定义 Choreographer 回调
class FrameMonitor {

    private var lastFrameTime = 0L

    private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
        if (lastFrameTime != 0L) {
            val duration = (frameTimeNanos - lastFrameTime) / 1_000_000 // ns → ms
            if (duration > 16) {
                Log.w("FrameMonitor", "Jank detected! Frame took ${duration}ms")
            }
        }
        lastFrameTime = frameTimeNanos
        Choreographer.getInstance().postFrameCallback(this)
    }

    fun start() {
        Choreographer.getInstance().postFrameCallback(frameCallback)
    }

    fun stop() {
        Choreographer.getInstance().removeFrameCallback(frameCallback)
    }
}

// 避免主线程 IO / 网络 / 数据库
// ❌ 在主线程执行耗时操作
class BadFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val result = database.query("SELECT * FROM products") // ANR 风险!
        updateUI(result)
    }
}

// ✅ 协程切换线程
class GoodFragment : Fragment() {
    private val viewModel: ProductViewModel by viewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.products.collect { products ->
                    // 已在主线程
                    adapter.submitList(products)
                }
            }
        }
    }
}

RecyclerView 性能优化

kotlin 复制代码
class ProductAdapter : ListAdapter<Product, ProductViewHolder>(ProductDiffCallback()) {

    // ✅ DiffUtil:只更新变化的 Item
    class ProductDiffCallback : DiffUtil.ItemCallback<Product>() {
        override fun areItemsTheSame(old: Product, new: Product) = old.id == new.id
        override fun areContentsTheSame(old: Product, new: Product) = old == new
    }

    // ✅ 使用 RecycledViewPool 在多个 RecyclerView 间共享 ViewHolder
    fun setupSharedPool(recyclerView1: RecyclerView, recyclerView2: RecyclerView) {
        val sharedPool = RecyclerView.RecycledViewPool()
        sharedPool.setMaxRecycledViews(0, 20)
        recyclerView1.setRecycledViewPool(sharedPool)
        recyclerView2.setRecycledViewPool(sharedPool)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
        val binding = ItemProductBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ProductViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
        holder.bind(getItem(position))
    }
}

// RecyclerView 配置
recyclerView.apply {
    // ✅ 固定大小不变时设置此项(跳过 requestLayout)
    setHasFixedSize(true)
    // ✅ 预加载更多 Item(避免滑动时加载)
    (layoutManager as LinearLayoutManager).initialPrefetchItemCount = 6
    // ✅ 图片加载用 Glide 并预拉取
    addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(rv: RecyclerView, newState: Int) {
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                Glide.with(context).resumeRequests()
            } else {
                Glide.with(context).pauseRequests()
            }
        }
    })
}

7.2 内存优化

常见内存泄漏场景

kotlin 复制代码
// ❌ 场景1:静态持有 Context(最常见)
object BadSingleton {
    var context: Context? = null // 持有 Activity Context → 内存泄漏!
}

// ✅ 使用 Application Context
object GoodSingleton {
    private lateinit var appContext: Context
    fun init(context: Context) { appContext = context.applicationContext }
}

// ❌ 场景2:内部类持有外部类引用
class BadActivity : AppCompatActivity() {
    private val handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            // 匿名内部类隐式持有 BadActivity 的引用
            updateUI() // Activity 已销毁时仍持有引用
        }
    }
}

// ✅ 使用静态内部类 + 弱引用
class GoodActivity : AppCompatActivity() {
    private val handler = MyHandler(WeakReference(this))

    private class MyHandler(private val activityRef: WeakReference<GoodActivity>)
        : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            activityRef.get()?.updateUI()
        }
    }

    private fun updateUI() { /* ... */ }
}

// ❌ 场景3:未取消的协程
class BadViewModel : ViewModel() {
    fun startJob() {
        GlobalScope.launch { // 不受 ViewModel 生命周期管理!
            delay(10_000)
            // ViewModel 已销毁,仍在运行
        }
    }
}

// ✅ 使用 viewModelScope
class GoodViewModel : ViewModel() {
    fun startJob() {
        viewModelScope.launch { // ViewModel 销毁时自动取消
            delay(10_000)
            // 安全
        }
    }
}

// ❌ 场景4:BroadcastReceiver 未注销
class BadActivity2 : AppCompatActivity() {
    private val receiver = object : BroadcastReceiver() { override fun onReceive(c: Context, i: Intent) {} }

    override fun onResume() {
        super.onResume()
        registerReceiver(receiver, IntentFilter("ACTION"))
        // 忘记在 onPause 中注销!
    }
}

// ✅ 配对注册/注销
class GoodActivity2 : AppCompatActivity() {
    private val receiver = object : BroadcastReceiver() { override fun onReceive(c: Context, i: Intent) {} }

    override fun onResume() { super.onResume(); registerReceiver(receiver, IntentFilter("ACTION")) }
    override fun onPause() { super.onPause(); unregisterReceiver(receiver) }
}

// ❌ 场景5:Fragment ViewBinding 泄漏
class BadFragment : Fragment() {
    private val binding: FragmentBadBinding by lazy {
        FragmentBadBinding.inflate(layoutInflater) // View 销毁后 binding 仍持有 View 引用
    }
}

// ✅ onDestroyView 清空 binding
class GoodFragment : Fragment() {
    private var _binding: FragmentGoodBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View {
        _binding = FragmentGoodBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null // ✅ 必须清空
    }
}

LeakCanary 集成

kotlin 复制代码
// build.gradle.kts
dependencies {
    debugImplementation("com.squareup.leakcanary:leakcanary-android:2.14")
}

// LeakCanary 会自动安装(无需代码配置)
// 检测到泄漏时会显示通知

// 自定义泄漏观察
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        if (LeakCanary.isInAnalyzerProcess(this)) return

        // 添加自定义对象监听(观察是否被回收)
        AppWatcher.objectWatcher.expectWeaklyReachable(
            object = someObject,
            description = "SomeObject should be collected after screen close"
        )
    }
}

图片内存优化

kotlin 复制代码
// Glide 配置
@GlideModule
class MyGlideModule : AppGlideModule() {
    override fun applyOptions(context: Context, builder: GlideBuilder) {
        // 内存缓存大小
        val memoryCacheSizeMB = 50
        builder.setMemoryCache(LruResourceCache(memoryCacheSizeMB * 1024 * 1024L))

        // 磁盘缓存
        builder.setDiskCache(
            InternalCacheDiskCacheFactory(context, "image_cache", 250 * 1024 * 1024L)
        )

        // 内存紧张时的策略
        builder.setDefaultRequestOptions(
            RequestOptions()
                .format(DecodeFormat.PREFER_RGB_565) // RGB_565 比 ARGB_8888 少一半内存
                .disallowHardwareConfig() // 在需要软件渲染时
        )
    }

    override fun isManifestParsingEnabled() = false
}

// 按需加载合适尺寸
Glide.with(imageView)
    .load(url)
    .override(imageView.width, imageView.height) // 只加载需要的尺寸
    .thumbnail(0.1f) // 先加载 10% 缩略图
    .placeholder(R.drawable.ic_placeholder)
    .error(R.drawable.ic_error)
    .into(imageView)

7.3 启动优化

冷启动流程

复制代码
用户点击图标
  ↓
Zygote fork(~50ms)
  ↓
Application.onCreate()(你的代码)
  ↓
Activity.onCreate() → onStart() → onResume()
  ↓
View 测量/布局/绘制
  ↓
第一帧显示 → TTFD(Time to First Display)
  ↓
数据加载完成 → TTCD(Time to Complete Display)
kotlin 复制代码
// ✅ 启动优化实践
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // ✅ 1. 只在主进程初始化
        if (isMainProcess()) {
            // ✅ 2. 按优先级初始化:关键 → 次要 → 懒加载
            initCritical() // 同步:Hilt、Database
            initAsync()    // 异步:Analytics、推送
        }
    }

    private fun initCritical() {
        // 快速初始化(<10ms)
    }

    private fun initAsync() {
        // 在后台线程初始化
        thread(name = "init-thread") {
            initAnalytics()
            initCrashReporter()
            initPushService()
        }
    }

    private fun isMainProcess(): Boolean {
        return processName == packageName
    }

    private val processName: String
        get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            getProcessName()
        } else {
            // 旧版方式
            ActivityManager::class.java.getMethod("getMyMemoryState").let { "" }
        }

    private fun initAnalytics() { /* ... */ }
    private fun initCrashReporter() { /* ... */ }
    private fun initPushService() { /* ... */ }
}

App Startup(Jetpack 启动库)

kotlin 复制代码
// build.gradle.kts
implementation("androidx.startup:startup-runtime:1.1.1")

// 定义 Initializer
class TimberInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
    }
    override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}

class AnalyticsInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        Analytics.initialize(context)
    }
    override fun dependencies(): List<Class<out Initializer<*>>> =
        listOf(TimberInitializer::class.java) // 依赖 Timber 先初始化
}

// 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.TimberInitializer"
        android:value="androidx.startup" />
    <meta-data
        android:name="com.example.AnalyticsInitializer"
        android:value="androidx.startup" />
</provider>

// 手动触发(懒初始化)
AppInitializer.getInstance(context)
    .initializeComponent(AnalyticsInitializer::class.java)

Baseline Profiles(基线配置文件)

kotlin 复制代码
// build.gradle.kts(app 模块)
plugins {
    id("androidx.baselineprofile")
}

dependencies {
    baselineProfile(project(":baselineprofile"))
}

// :baselineprofile 测试模块
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
    @get:Rule
    val rule = BaselineProfileRule()

    @Test
    fun generate() {
        rule.collect("com.example.myapp") {
            // 定义关键用户旅程(热身路径)
            pressHome()
            startActivityAndWait()
            // 滚动列表
            device.findObject(By.res("product_list")).scroll(Direction.DOWN, 3)
            // 打开详情
            device.findObject(By.res("product_item_0")).click()
            device.waitForIdle()
        }
    }
}

// 生成命令
// ./gradlew :baselineprofile:generateBaselineProfile

7.4 包体积优化

R8(混淆 + Tree Shaking)

groovy 复制代码
// build.gradle(Release 配置)
android {
    buildTypes {
        release {
            isMinifyEnabled = true      // 开启代码混淆
            isShrinkResources = true    // 移除未使用资源(需 minifyEnabled = true)
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}
复制代码
# proguard-rules.pro

# Kotlin 协程
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}

# Retrofit
-keepattributes Signature
-keepattributes Exceptions
-keep class retrofit2.** { *; }
-keepclasseswithmembers class * {
    @retrofit2.http.* <methods>;
}

# Room
-keep class * extends androidx.room.RoomDatabase
-dontwarn androidx.room.paging.**

# Gson
-keep class com.example.model.** { *; }

# 防止 ViewModel 被混淆
-keep class * extends androidx.lifecycle.ViewModel {
    <init>(...);
}

# Hilt
-keep class dagger.hilt.** { *; }
-keep @dagger.hilt.InstallIn class * { *; }

APK 分析与优化

bash 复制代码
# 分析 APK 内容(命令行)
./gradlew :app:bundleRelease

# Android Studio → Build → Analyze APK
# 查看:
# - classes.dex(代码)
# - res/(资源)
# - lib/(Native 库)
# - assets/(资产文件)

# 按 ABI 分包(减少每个用户下载的大小)
android {
    splits {
        abi {
            isEnable = true
            reset()
            include("arm64-v8a", "armeabi-v7a", "x86_64")
            isUniversalApk = false
        }
    }
}

# WebP 图片转换(比 PNG 小 25-35%)
# Android Studio → Refactor → Convert to WebP

资源压缩

kotlin 复制代码
// 保留特定资源(配合 shrinkResources 使用)
// res/raw/keep.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/keep_this,@drawable/keep_this_too"
    tools:discard="@layout/unused_layout" />

// 动态特性模块(Dynamic Feature Module)
// 将非核心功能拆分为按需下载的模块
plugins {
    id("com.android.dynamic-feature")
}
android {
    // 动态特性模块配置
}

7.5 电量与网络优化

WorkManager(后台任务)

kotlin 复制代码
// 网络同步 Worker
class SyncWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            val syncResult = syncRepository.sync()
            if (syncResult.isSuccess) Result.success()
            else Result.retry()
        } catch (e: NetworkUnavailableException) {
            Result.retry()
        } catch (e: Exception) {
            Result.failure(workDataOf("error" to e.message))
        }
    }

    companion object {
        fun schedule(workManager: WorkManager) {
            val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED) // 需要网络
                .setRequiresBatteryNotLow(true)                // 低电量时不运行
                .build()

            val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
                repeatInterval = 1,
                repeatIntervalTimeUnit = TimeUnit.HOURS
            )
                .setConstraints(constraints)
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
                .addTag("sync")
                .build()

            workManager.enqueueUniquePeriodicWork(
                "periodic_sync",
                ExistingPeriodicWorkPolicy.UPDATE,
                syncRequest
            )
        }

        // 链式任务
        fun scheduleChain(workManager: WorkManager) {
            val cleanupRequest = OneTimeWorkRequestBuilder<CleanupWorker>().build()
            val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>().build()
            val notifyRequest = OneTimeWorkRequestBuilder<NotifyWorker>().build()

            workManager
                .beginWith(cleanupRequest)
                .then(syncRequest)
                .then(notifyRequest)
                .enqueue()
        }
    }
}

// 监听 WorkInfo
class SyncViewModel @Inject constructor(
    private val workManager: WorkManager
) : ViewModel() {

    val syncState: LiveData<WorkInfo?> = workManager
        .getWorkInfosByTagLiveData("sync")
        .map { workInfos -> workInfos.firstOrNull() }
}

网络请求批量处理

kotlin 复制代码
// 减少请求次数:批量合并
class BatchRequestManager {
    private val pendingIds = mutableListOf<Int>()
    private var debounceJob: Job? = null

    fun requestProduct(id: Int, scope: CoroutineScope, onResult: (List<Product>) -> Unit) {
        pendingIds.add(id)
        debounceJob?.cancel()
        debounceJob = scope.launch {
            delay(50) // 等待 50ms 收集批量请求
            val ids = pendingIds.toList()
            pendingIds.clear()
            onResult(api.getProductsBatch(ids))
        }
    }
}

7.6 Compose 性能调优

减少不必要的重组

kotlin 复制代码
// ❌ 导致过多重组
@Composable
fun BadList(viewModel: MyViewModel) {
    val state by viewModel.state.collectAsState()
    // state 中任何字段变化,整个 LazyColumn 都重组
    LazyColumn {
        items(state.products) { product ->
            // 即使 product 未变化,也可能重组
            ProductCard(product)
        }
    }
}

// ✅ 精确订阅需要的数据
@Composable
fun GoodList(viewModel: MyViewModel) {
    val products by viewModel.products.collectAsStateWithLifecycle()
    LazyColumn {
        items(products, key = { it.id }) { product ->
            // key 确保 product 未变化时不重组
            ProductCard(product)
        }
    }
}

// ✅ 稳定类型(Stable)减少重组
@Immutable // 告诉 Compose 此类型不可变
data class Product(val id: Int, val name: String, val price: Double)

// ✅ @Stable 用于可能可变但 Compose 可追踪的类型
@Stable
class ShoppingCart {
    var items by mutableStateOf(emptyList<CartItem>())
}

// ✅ derivedStateOf:只在计算结果变化时触发重组
@Composable
fun OptimizedScrollToTop(listState: LazyListState) {
    val showButton by remember {
        derivedStateOf { listState.firstVisibleItemIndex > 0 }
    }
    // 只在 showButton 从 false→true 或 true→false 时重组
    AnimatedVisibility(visible = showButton) {
        ScrollToTopButton()
    }
}

// ✅ remember 缓存昂贵计算
@Composable
fun ExpensiveComputation(products: List<Product>, filter: String) {
    val filteredProducts = remember(products, filter) {
        // 只在 products 或 filter 变化时重新计算
        products.filter { it.name.contains(filter, ignoreCase = true) }
            .sortedBy { it.price }
    }
    // 使用 filteredProducts
}

避免在重组时分配对象

kotlin 复制代码
// ❌ 每次重组都创建新 lambda(导致 Button 重组)
@Composable
fun BadButton(item: Item) {
    Button(onClick = { handleClick(item) }) { Text("点击") }
    // onClick lambda 每次重组都是新对象,Button 无法判断是否需要重组
}

// ✅ 使用 remember 包装 lambda
@Composable
fun GoodButton(item: Item, onItemClick: (Item) -> Unit) {
    // 将 onClick 提升到父组件,父组件用 remember 缓存
    Button(onClick = { onItemClick(item) }) { Text("点击") }
}

// 父组件中
@Composable
fun Parent(viewModel: MyViewModel) {
    val onItemClick: (Item) -> Unit = remember(viewModel) {
        { item -> viewModel.onItemClick(item) }
    }
    GoodButton(item = someItem, onItemClick = onItemClick)
}

// ✅ 避免在 Modifier 中实例化动画规格
@Composable
fun AnimatedItem(visible: Boolean) {
    val animSpec = remember { tween<Float>(durationMillis = 300) }
    val alpha by animateFloatAsState(if (visible) 1f else 0f, animSpec, label = "alpha")
    Box(Modifier.alpha(alpha)) { /* ... */ }
}

Compose Layout Inspector & Recomposition Counter

kotlin 复制代码
// 开启重组高亮(Android Studio)
// Profiler → Compose → Recomposition Highlighter

// 手动追踪重组次数(调试用)
var recompositionCount = 0
@Composable
fun DebugRecomposition(name: String, content: @Composable () -> Unit) {
    SideEffect {
        recompositionCount++
        Log.d("Compose", "$name recomposed $recompositionCount times")
    }
    content()
}

Demo 代码:chapter07

kotlin 复制代码
// chapter07/PerformanceDemo.kt
package com.example.androiddemos.chapter07

import androidx.compose.animation.core.tween
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.unit.dp

// 演示1:derivedStateOf 优化
@Composable
fun DerivedStateDemo() {
    val listState = rememberLazyListState()

    // ✅ derivedStateOf 避免高频重组
    val showTopButton by remember {
        derivedStateOf { listState.firstVisibleItemIndex > 3 }
    }

    Box(modifier = Modifier.fillMaxSize()) {
        LazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items((1..50).toList(), key = { it }) { index ->
                ListItem(
                    headlineContent = { Text("列表项 $index") },
                    modifier = Modifier.padding(horizontal = 16.dp)
                )
                Divider()
            }
        }

        AnimatedVisibility(
            visible = showTopButton,
            modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp)
        ) {
            FloatingActionButton(onClick = {
                /* 滚动到顶部 */
            }) {
                Text("↑")
            }
        }
    }
}

// 演示2:remember 缓存昂贵计算
@Composable
fun RememberOptimizationDemo() {
    val allItems = remember { (1..100).map { "产品 $it:¥${it * 9.9}" } }
    var filterText by remember { mutableStateOf("") }

    // ✅ remember(filterText):只在 filterText 变化时重新过滤
    val filteredItems = remember(filterText) {
        if (filterText.isBlank()) allItems
        else allItems.filter { it.contains(filterText) }
    }

    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        Text("性能优化 Demo", style = MaterialTheme.typography.headlineSmall)
        Spacer(Modifier.height(8.dp))
        OutlinedTextField(
            value = filterText,
            onValueChange = { filterText = it },
            label = { Text("搜索过滤") },
            modifier = Modifier.fillMaxWidth()
        )
        Text("${filteredItems.size} 条结果", style = MaterialTheme.typography.bodySmall)
        Spacer(Modifier.height(8.dp))
        LazyColumn {
            items(filteredItems, key = { it }) { item ->
                Text(item, modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp))
                Divider()
            }
        }
    }
}

// 演示3:动画性能
@Composable
fun AnimationPerformanceDemo() {
    var isVisible by remember { mutableStateOf(true) }
    val animSpec = remember { tween<Float>(durationMillis = 500) }
    val alpha by animateFloatAsState(if (isVisible) 1f else 0f, animSpec, label = "alpha")

    Column(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text("动画性能 Demo", style = MaterialTheme.typography.headlineSmall)
        Spacer(Modifier.height(24.dp))

        Card(
            modifier = Modifier.size(200.dp).alpha(alpha)
        ) {
            Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                Text("动画内容", style = MaterialTheme.typography.headlineMedium)
            }
        }

        Spacer(Modifier.height(24.dp))
        Button(onClick = { isVisible = !isVisible }) {
            Text(if (isVisible) "隐藏(淡出)" else "显示(淡入)")
        }
    }
}

章节总结

知识点 必掌握程度 面试频率
主线程 / Jank / 16ms 原则 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
内存泄漏 5 大场景 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
LeakCanary 使用 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
冷启动优化 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Baseline Profiles ⭐⭐⭐⭐ ⭐⭐⭐
R8 混淆与 shrinkResources ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
WorkManager 约束条件 ⭐⭐⭐⭐ ⭐⭐⭐⭐
Compose derivedStateOf ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Compose @Stable/@Immutable ⭐⭐⭐⭐ ⭐⭐⭐⭐
RecyclerView DiffUtil ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐

👉 下一章:第八章------工程化与模块化

相关推荐
全栈工程师修炼指南2 小时前
Nginx | 磁盘IO层面性能优化秘诀:error 日志内存环形缓冲区及小文件 sendfile 零拷贝技术
运维·网络·nginx·性能优化
空中海3 小时前
第四章:导航与路由
android
MU在掘金916953 小时前
在Perfetto里框选一段卡顿,AI直接告诉你哪行代码有问题
性能优化
迷藏4944 小时前
**TiDB 在高并发场景下的性能优化实战:从慢查询到极致吞吐的跃迁**在现代分布式系统中,数据库不仅是数据存储的
java·数据库·python·性能优化·tidb
2501_916007474 小时前
iOS逆向工程:详细解析ptrace反调试机制的破解方法与实战步骤
android·macos·ios·小程序·uni-app·cocoa·iphone
空中海5 小时前
第三章:状态管理与 Jetpack 架构组件
android·架构
峥嵘life5 小时前
Android + Kiro AI软件开发实战教程
android·后端·学习
流星雨在线5 小时前
安卓路由技术选型调研
android·therouter·arouter
千里马学框架5 小时前
Ubuntu 24 搭建aosp源码环境详细笔记
android·linux·ubuntu·framework·安卓·aosp·源码环境