在 Android 开发中,性能优化 是中后期稳定性和用户体验的关键工作,优化的目标是让 应用运行更流畅、内存更省、耗电更低、启动更快、界面不卡顿。
下面我会系统性地分析 Android 性能优化的各个方向,并附带一些关键代码示例(含注释)。
🧭 一、性能优化的主要方向
| 优化方向 | 目标 | 常见手段 |
|---|---|---|
| 启动优化 | 缩短冷启动/热启动时间 | 延迟初始化、启动页优化 |
| 内存优化 | 降低内存占用、防止 OOM | 使用内存分析工具、合理管理 Bitmap |
| 绘制优化 | 提升界面流畅度 | 避免过度绘制、减少层级 |
| 布局优化 | 提高渲染效率 | ConstraintLayout、ViewStub、Merge 标签 |
| I/O 优化 | 降低磁盘/网络延迟 | 异步加载、缓存、压缩 |
| 线程优化 | 防止主线程卡顿 | 使用协程、Handler、Executor |
| 电量优化 | 降低耗电 | 降低后台唤醒频率、批量任务处理 |
| 数据结构优化 | 提高算法效率 | 使用 SparseArray、LruCache 等 |
| 动画优化 | 流畅不卡顿 | 使用硬件加速、Property Animation |
🚀 二、启动优化(App 启动速度)
启动时间太长会让用户误以为应用卡死。
✅ 优化思路:
-
延迟加载不必要模块(例如广告、推送)
-
Application 中只做必要初始化
-
使用异步初始化
class App : Application() {
override fun onCreate() {
super.onCreate()
// ✅ 必要初始化(立即执行)
initLogger()
// ⚙️ 非必要初始化(异步延迟执行)
GlobalScope.launch(Dispatchers.Default) {
initAnalytics()
initPushService()
}
}
}
🧠 三、内存优化(Memory Leak / OOM)
常见内存泄漏场景:Activity 引用未释放、Handler 匿名类、单例持有 Context。
✅ 示例:使用 WeakReference 避免 Handler 内存泄漏
class SafeHandler(activity: Activity) : Handler(Looper.getMainLooper()) {
private val weakRef = WeakReference(activity)
override fun handleMessage(msg: Message) {
val act = weakRef.get() ?: return
when (msg.what) {
1 -> act.showToast("任务完成")
}
}
}
🎨 四、绘制与布局优化
布局过于复杂会导致 UI 卡顿、渲染慢。
✅ 使用 ConstraintLayout 代替多层嵌套布局
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 多个布局通过约束定位,减少嵌套 -->
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
✅ 使用 ViewStub 延迟加载不常用布局
<ViewStub
android:id="@+id/vs_empty"
android:layout="@layout/layout_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
// 当需要显示空布局时再加载,减少初始布局解析
val emptyView = binding.vsEmpty.inflate()
💾 五、I/O 与网络优化
I/O 阻塞会导致主线程 ANR。
✅ 异步加载 + 缓存策略
suspend fun loadData(): String = withContext(Dispatchers.IO) {
// 优先读缓存
val cache = getCache("data.json")
if (cache != null) return@withContext cache
// 缓存不存在则请求网络
val response = apiService.getData()
saveCache("data.json", response)
return@withContext response
}
⚙️ 六、线程优化(避免主线程卡顿)
所有耗时操作都应放在子线程执行。
✅ 协程方式处理耗时任务
lifecycleScope.launch {
showLoading()
val data = withContext(Dispatchers.IO) {
// 耗时操作,如数据库或网络请求
fetchUserInfo()
}
updateUI(data)
hideLoading()
}
🔋 七、电量优化
减少后台唤醒与频繁网络请求。
✅ 批量上传日志(而非每次事件都上传)
private val logs = mutableListOf<String>()
fun logEvent(event: String) {
logs.add(event)
if (logs.size >= 10) {
uploadLogs()
}
}
🧮 八、数据结构优化
使用合适的数据结构能显著提升性能。
✅ 使用 SparseArray 替代 HashMap(key 为 Int 时)
val map = SparseArray<String>()
map.put(1, "Hello")
map.put(2, "World")
Log.d("TAG", map[1]) // 输出 Hello
✅ 使用 LruCache 缓存 Bitmap
val cache = LruCache<String, Bitmap>(10 * 1024 * 1024) // 10MB 缓存
cache.put("avatar", bitmap)
val bmp = cache.get("avatar")
📊 九、工具与检测
| 工具 | 功能 |
|---|---|
| Android Profiler | 查看 CPU、内存、网络使用情况 |
| LeakCanary | 自动检测内存泄漏 |
| StrictMode | 检测主线程耗时操作 |
| Systrace / Perfetto | 分析卡顿、掉帧问题 |
| MAT / Profiler Heap Dump | 深度分析内存占用 |
✅ 总结
Android 性能优化的核心思想是:
让主线程更轻、内存更省、布局更扁平、数据加载更聪明。
优化不是一次性的,而是一个持续监测与调优的过程。
推荐在开发周期中定期使用 Profiler 检测应用性能,及时发现瓶颈。
以下是实例:
一、内存优化
1. 内存泄漏检测与预防
import android.content.Context
import android.os.Handler
import android.os.Looper
import java.lang.ref.WeakReference
/**
* 内存泄漏常见场景及解决方案
* 1. Handler内存泄漏
* 2. 静态变量持有Context
* 3. 匿名内部类持有外部类引用
* 4. 资源未及时释放
*/
class MemoryOptimizationDemo {
// ❌ 错误示例:静态变量持有Context导致内存泄漏
companion object {
private var sContext: Context? = null // 静态变量持有Context
fun setContext(context: Context) {
sContext = context // 这会导致Activity无法被回收
}
}
// ✅ 正确示例:使用Application Context或弱引用
companion object {
private var sAppContext: WeakReference<Context>? = null
fun setContext(context: Context) {
// 使用Application Context而不是Activity Context
sAppContext = WeakReference(context.applicationContext)
}
}
private val mainHandler = Handler(Looper.getMainLooper())
private var runnable: Runnable? = null
/**
* ❌ 错误示例:Handler导致的内存泄漏
* 匿名Runnable隐式持有外部类引用
*/
fun startProblematicTask() {
runnable = object : Runnable {
override fun run() {
// 执行任务
mainHandler.postDelayed(this, 1000) // 循环执行
}
}
mainHandler.postDelayed(runnable!!, 1000)
}
/**
* ✅ 正确示例:使用静态内部类+弱引用
*/
fun startOptimizedTask() {
val task = SafeRunnable(this)
mainHandler.postDelayed(task, 1000)
}
private fun doWork() {
// 执行具体工作
}
/**
* 静态内部类,不持有外部类引用
*/
private class SafeRunnable(outer: MemoryOptimizationDemo) : Runnable {
// 使用弱引用,避免内存泄漏
private val outerRef: WeakReference<MemoryOptimizationDemo> = WeakReference(outer)
override fun run() {
val outer = outerRef.get()
outer?.doWork()
// 注意:这里不再自动循环,由外部控制生命周期
}
}
/**
* 及时清理资源
*/
fun cleanup() {
// 移除所有回调
mainHandler.removeCallbacksAndMessages(null)
runnable = null
}
}
2. 图片内存优化
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.LruCache
/**
* 图片内存优化管理类
* 1. 使用LruCache进行内存缓存
* 2. 图片采样压缩
* 3. 使用合适的Bitmap.Config
* 4. 及时回收Bitmap
*/
class ImageMemoryManager(context: Context) {
private val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
private val cacheSize = maxMemory / 8 // 使用1/8的可用内存作为缓存
// LruCache内存缓存
private val memoryCache: LruCache<String, Bitmap> = object : LruCache<String, Bitmap>(cacheSize) {
override fun sizeOf(key: String, bitmap: Bitmap): Int {
// 返回Bitmap占用的内存大小,单位KB
return bitmap.byteCount / 1024
}
override fun entryRemoved(evicted: Boolean, key: String,
oldValue: Bitmap, newValue: Bitmap?) {
// 当Bitmap被移除时,可以在这里进行回收
if (evicted) {
oldValue.recycle()
}
}
}
/**
* 从内存缓存获取Bitmap
*/
fun getBitmapFromMemory(key: String): Bitmap? {
return memoryCache.get(key)
}
/**
* 添加Bitmap到内存缓存
*/
fun addBitmapToMemory(key: String, bitmap: Bitmap) {
if (getBitmapFromMemory(key) == null) {
memoryCache.put(key, bitmap)
}
}
/**
* 加载压缩后的图片
* @param filePath 图片文件路径
* @param reqWidth 目标宽度
* @param reqHeight 目标高度
*/
fun decodeSampledBitmapFromFile(filePath: String, reqWidth: Int, reqHeight: Int): Bitmap {
// 第一次解析只获取图片尺寸,不加载像素数据
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
BitmapFactory.decodeFile(filePath, options)
// 计算采样率
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
// 使用RGB_565减少内存占用(如果不需要透明度)
options.inPreferredConfig = Bitmap.Config.RGB_565
options.inJustDecodeBounds = false
return BitmapFactory.decodeFile(filePath, options) ?:
throw IllegalArgumentException("无法解码图片: $filePath")
}
/**
* 计算合适的采样率
*/
private fun calculateInSampleSize(options: BitmapFactory.Options,
reqWidth: Int, reqHeight: Int): Int {
val (width, height) = options.run { outWidth to outHeight }
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
val halfHeight = height / 2
val halfWidth = width / 2
// 计算最大的采样率,保证图片尺寸大于等于目标尺寸
while (halfHeight / inSampleSize >= reqHeight &&
halfWidth / inSampleSize >= reqWidth) {
inSampleSize *= 2
}
}
return inSampleSize
}
/**
* 清理缓存
*/
fun clearCache() {
memoryCache.evictAll()
}
}
二、布局优化
1. 布局层级优化
<!-- ❌ 错误示例:嵌套过深的布局 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- ✅ 优化示例:使用ConstraintLayout减少嵌套 -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/iv_icon"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@id/iv_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_icon" />
<TextView
android:id="@+id/tv_subtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/tv_title"
app:layout_constraintEnd_toEndOf="@id/tv_title"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
2. ViewStub延迟加载
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewStub
import androidx.appcompat.app.AppCompatActivity
/**
* 使用ViewStub优化布局加载
* ViewStub是轻量级View,只有在需要时才inflate实际布局
*/
class ViewStubOptimizationActivity : AppCompatActivity() {
private var errorViewStub: ViewStub? = null
private var errorView: View? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewstub_optimization)
// 初始化ViewStub(此时不会加载实际布局)
errorViewStub = findViewById(R.id.vs_error)
// 模拟网络请求
loadData()
}
private fun loadData() {
// 模拟网络请求
Thread {
Thread.sleep(2000)
runOnUiThread {
// 假设请求失败,显示错误页面
showErrorView()
}
}.start()
}
/**
* 显示错误页面(只有这时才会实际加载错误布局)
*/
private fun showErrorView() {
if (errorView == null) {
// 第一次调用时才会inflate实际布局
errorView = errorViewStub?.inflate()
} else {
errorView?.visibility = View.VISIBLE
}
// 设置错误页面内容
errorView?.findViewById<View>(R.id.btn_retry)?.setOnClickListener {
// 重试逻辑
errorView?.visibility = View.GONE
loadData()
}
}
}
三、网络优化
import okhttp3.Cache
import okhttp3.CacheControl
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.util.concurrent.TimeUnit
/**
* 网络请求优化配置
* 1. 连接池复用
* 2. 请求缓存
* 3. 超时优化
* 4. 数据压缩
*/
class NetworkOptimizationManager(private val context: Context) {
companion object {
private const val CACHE_SIZE = 10 * 1024 * 1024L // 10MB缓存
private const val CONNECT_TIMEOUT = 15L
private const val READ_TIMEOUT = 30L
private const val WRITE_TIMEOUT = 30L
}
private val cacheDir by lazy {
File(context.cacheDir, "http_cache")
}
private val cache by lazy {
Cache(cacheDir, CACHE_SIZE)
}
/**
* 创建优化的OkHttpClient
*/
fun createOptimizedHttpClient(): OkHttpClient {
return OkHttpClient.Builder().apply {
// 连接池配置(默认已优化)
connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
// 超时配置
connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
// 缓存配置
cache(cache)
// 添加拦截器进行统一优化
addInterceptor { chain ->
val originalRequest = chain.request()
// 添加公共头部
val requestBuilder = originalRequest.newBuilder()
.header("Accept-Encoding", "gzip") // 启用Gzip压缩
.header("Connection", "keep-alive") // 保持连接
.method(originalRequest.method, originalRequest.body)
// 网络不可用时使用缓存
if (!isNetworkAvailable()) {
requestBuilder.cacheControl(
CacheControl.Builder()
.onlyIfCached()
.maxStale(7, TimeUnit.DAYS) // 最大缓存时间
.build()
)
}
val response = chain.proceed(requestBuilder.build())
// 统一处理响应
response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=300") // 5分钟缓存
.build()
}
// 调试日志(仅Debug模式开启)
if (BuildConfig.DEBUG) {
addInterceptor(
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
)
}
// 失败重试
retryOnConnectionFailure(true)
}.build()
}
/**
* 创建Retrofit实例
*/
fun createRetrofit(baseUrl: String): Retrofit {
return Retrofit.Builder()
.baseUrl(baseUrl)
.client(createOptimizedHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
/**
* 检查网络是否可用
*/
private fun isNetworkAvailable(): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE)
as? android.net.ConnectivityManager
return connectivityManager?.activeNetworkInfo?.isConnected == true
}
}
四、启动优化
import android.app.Application
import android.content.Context
import android.os.StrictMode
import androidx.startup.Initializer
import com.facebook.drawee.backends.pipeline.Fresco
/**
* 应用启动优化
* 1. 异步初始化
* 2. 延迟初始化
* 3. 多进程优化
* 4. StrictMode检测
*/
class AppStartupOptimization : Application() {
override fun onCreate() {
super.onCreate()
// 主线程初始化必要组件
initMainThreadComponents()
// 后台线程初始化非紧急组件
initBackgroundComponents()
// 仅在Debug模式开启StrictMode
if (BuildConfig.DEBUG) {
enableStrictMode()
}
}
/**
* 必须在主线程初始化的组件
*/
private fun initMainThreadComponents() {
// 必须主线程初始化的组件
}
/**
* 在后台线程初始化的组件
*/
private fun initBackgroundComponents() {
Thread {
// 设置线程优先级,避免影响主线程
Thread.currentThread().priority = Thread.MIN_PRIORITY
// 初始化第三方SDK等耗时操作
initThirdPartyLibraries()
// 预加载数据
preloadData()
}.start()
}
private fun initThirdPartyLibraries() {
// 例如:Fresco、统计SDK等
}
private fun preloadData() {
// 预加载常用数据
}
/**
* 启用StrictMode检测主线程违规操作
*/
private fun enableStrictMode() {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll() // 检测所有违规
.penaltyLog() // 违规时打印日志
.penaltyDeath() // 违规时崩溃(仅Debug)
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectActivityLeaks() // 检测Activity泄漏
.detectLeakedClosableObjects() // 检测未关闭对象
.detectLeakedSqlLiteObjects() // 检测数据库泄漏
.penaltyLog()
.build()
)
}
}
/**
* 使用App Startup库进行初始化优化
*/
class FrescoInitializer : Initializer<Unit> {
override fun create(context: Context) {
// 初始化Fresco
Fresco.initialize(context)
}
override fun dependencies(): List<Class<out Initializer<*>>> {
// 定义依赖关系
return emptyList()
}
}
五、数据库优化
import android.content.ContentValues
import android.database.Cursor
import androidx.room.*
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.sqlite.db.SupportSQLiteQuery
/**
* Room数据库优化
* 1. 索引优化
* 2. 事务批量操作
* 3. 查询优化
* 4. 数据库升级优化
*/
@Database(
entities = [User::class, Order::class],
version = 1,
exportSchema = false
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
abstract fun orderDao(): OrderDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database.db"
).apply {
// 查询时在后台线程执行
allowMainThreadQueries() // ❌ 生产环境不要使用
// 添加回调进行数据库优化
addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
// 数据库创建时的优化
db.execSQL("PRAGMA journal_mode = WAL") // 启用WAL模式
db.execSQL("PRAGMA synchronous = NORMAL") // 同步模式优化
db.execSQL("PRAGMA cache_size = 10000") // 缓存大小
}
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
// 每次打开数据库时的优化
db.execSQL("PRAGMA optimize") // 优化数据库
}
})
// 数据库升级策略
addMigrations(MIGRATION_1_2)
}.build()
}
// 数据库迁移示例
private val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
// 执行迁移SQL
database.execSQL("ALTER TABLE user ADD COLUMN last_login_time INTEGER")
}
}
}
}
/**
* 用户实体类 - 使用索引优化
*/
@Entity(
tableName = "user",
indices = [
Index(value = ["email"], unique = true), // 唯一索引
Index(value = ["name"]), // 普通索引
Index(value = ["age", "city"]) // 复合索引
]
)
data class User(
@PrimaryKey(autoGenerate = true)
val id: Long = 0,
@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "email")
val email: String,
@ColumnInfo(name = "age")
val age: Int,
@ColumnInfo(name = "city")
val city: String,
@ColumnInfo(name = "last_login_time")
val lastLoginTime: Long? = null
)
/**
* 用户数据访问对象 - 查询优化
*/
@Dao
interface UserDao {
/**
* 插入用户(使用事务批量插入)
*/
@Insert
suspend fun insertUser(user: User)
/**
* 批量插入用户 - 使用事务优化
*/
@Transaction
suspend fun insertUsers(users: List<User>) {
users.forEach { insertUser(it) }
}
/**
* 查询优化 - 只查询需要的字段
*/
@Query("SELECT id, name FROM user WHERE age > :minAge")
suspend fun getUsersAboveAge(minAge: Int): List<UserBrief>
/**
* 使用索引优化查询
*/
@Query("SELECT * FROM user WHERE name LIKE :name AND city = :city")
suspend fun findUsersByNameAndCity(name: String, city: String): List<User>
/**
* 分页查询优化
*/
@Query("SELECT * FROM user ORDER BY id LIMIT :pageSize OFFSET :offset")
suspend fun getUsersPaged(pageSize: Int, offset: Int): List<User>
/**
* 使用原生SQL进行复杂查询优化
*/
@RawQuery
suspend fun executeOptimizedQuery(query: SupportSQLiteQuery): List<User>
}
/**
* 用户简要信息 - 投影查询优化
*/
data class UserBrief(
val id: Long,
val name: String
)
/**
* 类型转换器
*/
class Converters {
@TypeConverter
fun fromTimestamp(value: Long?): Date? {
return value?.let { Date(it) }
}
@TypeConverter
fun dateToTimestamp(date: Date?): Long? {
return date?.time
}
}
六、性能监控工具
import android.os.Debug
import android.os.SystemClock
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
/**
* 性能监控工具类
* 1. 帧率监控
* 2. 内存监控
* 3. CPU监控
* 4. 启动时间监控
*/
class PerformanceMonitor private constructor() {
companion object {
@Volatile
private var instance: PerformanceMonitor? = null
fun getInstance(): PerformanceMonitor {
return instance ?: synchronized(this) {
instance ?: PerformanceMonitor().also { instance = it }
}
}
}
private val scheduler = Executors.newScheduledThreadPool(1)
private var monitoringTask: ScheduledFuture<*>? = null
private var frameRateListener: ((Int) -> Unit)? = null
private var memoryUsageListener: ((Long) -> Unit)? = null
private var frameCount = 0
private var lastFrameTime = 0L
/**
* 开始监控帧率
*/
fun startFrameRateMonitoring(listener: (Int) -> Unit) {
this.frameRateListener = listener
lastFrameTime = SystemClock.elapsedRealtime()
monitoringTask = scheduler.scheduleAtFixedRate({
val currentTime = SystemClock.elapsedRealtime()
val elapsed = currentTime - lastFrameTime
if (elapsed >= 1000) { // 每秒计算一次帧率
val fps = (frameCount * 1000 / elapsed).toInt()
frameRateListener?.invoke(fps)
frameCount = 0
lastFrameTime = currentTime
}
}, 0, 16, TimeUnit.MILLISECONDS) // 每16ms执行一次(约60fps)
}
/**
* 记录一帧渲染完成
*/
fun onFrameRendered() {
frameCount++
}
/**
* 获取当前内存使用情况
*/
fun getMemoryUsage(): Long {
val runtime = Runtime.getRuntime()
return runtime.totalMemory() - runtime.freeMemory()
}
/**
* 开始内存监控
*/
fun startMemoryMonitoring(listener: (Long) -> Unit) {
this.memoryUsageListener = listener
scheduler.scheduleAtFixedRate({
val memoryUsage = getMemoryUsage()
memoryUsageListener?.invoke(memoryUsage)
}, 0, 2, TimeUnit.SECONDS) // 每2秒检查一次内存
}
/**
* 停止所有监控
*/
fun stopMonitoring() {
monitoringTask?.cancel(true)
monitoringTask = null
frameRateListener = null
memoryUsageListener = null
frameCount = 0
}
/**
* 检测是否在主线程
*/
fun isOnMainThread(): Boolean {
return Looper.getMainLooper().thread == Thread.currentThread()
}
/**
* 方法执行时间监控
*/
inline fun <T> measureTime(operationName: String, block: () -> T): T {
val startTime = System.nanoTime()
try {
return block()
} finally {
val duration = (System.nanoTime() - startTime) / 1_000_000 // 转换为毫秒
if (duration > 16) { // 超过一帧时间(16ms)
Log.w("Performance", "$operationName 执行耗时: ${duration}ms")
}
}
}
}
简单来说:
-
内存优化:
-
使用弱引用避免内存泄漏
-
及时回收Bitmap等大对象
-
使用LruCache合理管理缓存
-
-
布局优化:
-
减少布局层级
-
使用ConstraintLayout
-
善用ViewStub和Merge
-
-
网络优化:
-
合理使用缓存
-
连接复用
-
数据压缩
-
-
启动优化:
-
异步初始化
-
延迟加载
-
多进程优化
-
-
数据库优化:
-
使用索引
-
事务批量操作
-
查询字段优化
-
-
监控工具:
-
实时监控性能指标
-
定位性能瓶颈
-
持续优化改进
-

576

被折叠的 条评论
为什么被折叠?



