跳到主要内容

IO 性能优化

问题

Android 应用中的 IO 操作有哪些性能隐患?如何优化?

答案

主线程 IO 的危害

主线程进行磁盘 IO 是 ANR 的常见原因之一。即使单次 IO 很快,在磁盘繁忙或存储空间不足时也可能耗时数百毫秒。

StrictMode 检测

if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.penaltyLog()
.build()
)
}
// 日志输出示例:
// D/StrictMode: StrictMode policy violation:
// android.os.StrictMode$StrictModeDiskReadViolation

常见 IO 优化

场景问题优化
SharedPreferencesgetString() 首次加载阻塞主线程改用 DataStore
文件读写主线程同步读写withContext(Dispatchers.IO)
数据库查询主线程 queryRoom + suspend / Flow
Bitmap 解码BitmapFactory.decodeFile 阻塞Coil/Glide 异步加载
JSON 解析大文件一次性解析流式解析(JsonReader)

批量写入优化

// ❌ 逐条插入
for (item in items) {
db.itemDao().insert(item) // 每次一个事务
}

// ✅ 批量插入(单事务)
db.withTransaction {
db.itemDao().insertAll(items)
}

MMKV 替代 SP

// MMKV 基于 mmap,性能远超 SharedPreferences
val mmkv = MMKV.defaultMMKV()
mmkv.encode("key", "value")
val value = mmkv.decodeString("key")
特性SharedPreferencesDataStoreMMKV
写入速度慢(XML)中等极快(mmap)
线程安全apply() 可能丢失
多进程
类型安全

常见面试问题

Q1: SP 的 apply() 为什么可能导致 ANR?

答案

apply() 虽然异步写入磁盘,但 Activity 在 onPause()onStop() 时会通过 QueuedWork.waitToFinish() 等待所有 SP 的异步写入完成。如果写入量大或磁盘慢,主线程会被阻塞导致 ANR。

Q2: 大文件 JSON 如何高效解析?

答案

使用流式解析(Streaming Parser)而非一次性加载到内存:

// Gson 流式解析
val reader = JsonReader(FileReader(file))
reader.beginArray()
while (reader.hasNext()) {
val item = gson.fromJson<Item>(reader, Item::class.java)
processItem(item)
}
reader.endArray()

相关链接