一个配置让 Glide 的加载效率提升 20%

5 阅读2分钟

仅对于图片加载场景

  1. 使用 OkHttp 替代 Glide 默认网络加载,优先使用 HTTP2
  2. 扩大 maxRequestsPerHost 可同一时间加载更多任务,默认只有 5 个,对于加载图片的场景远远不够
  3. 扩大 GlideExecutor 的加载任务,可同时请求更多数据,默认只有 4 个,在网络好时或者高端机适当扩大
  4. 使用 HttpDns,避免劫持和 加快 DNS 解析,DNS 解析可提前初始化
  5. 做好机型适配,避免低端机 OOM

操作步骤

引入 OkHttp 替代 Glide 默认加载

implementation com.github.bumptech.glide:okhttp3-integration:version

优化 OkhttpClient 加载配置

@GlideModule
class NetMonitorGlideModule : AppGlideModule() {

    private var okHttpClient: OkHttpClient? = null

    override fun applyOptions(context: Context, builder: com.bumptech.glide.GlideBuilder) {
        // 动态获取线程数
        val config = getConfig(context)

        val sourceExecutor = GlideExecutor.newSourceBuilder()
            .setThreadCount(config.glideThreadCount)
            .setName("source-executor")
            .setUncaughtThrowableStrategy(GlideExecutor.UncaughtThrowableStrategy.LOG)
            .build()

        builder.setSourceExecutor(sourceExecutor)
    }

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        if (okHttpClient == null) {
            okHttpClient = createGlideOkhttpClient(context)
        }

        // 替换 Glide 的默认网络加载器
        registry.replace(
            GlideUrl::class.java,
            InputStream::class.java,
            OkHttpUrlLoader.Factory(okHttpClient!!)
        )
    }

    private fun createGlideOkhttpClient(context: Context): OkHttpClient {

        // 动态并发控制
        val config = getConfig(context)
        val dispatcher = okhttp3.Dispatcher().apply {
            maxRequestsPerHost = config.maxRequestsPerHost
        }

        return OkHttpClient.Builder()
            .dispatcher(dispatcher)
            .connectTimeout(8, TimeUnit.SECONDS)
            .readTimeout(15, TimeUnit.SECONDS)
            .writeTimeout(15, TimeUnit.SECONDS)
            .connectionPool(
                ConnectionPool(
                    config.maxIdleConnections,     // 保留更多连接
                    5L, TimeUnit.MINUTES
                )
            )
            .retryOnConnectionFailure(true)
            .dns(AliDNS.getInstance(context))
            .build()
    }

    override fun isManifestParsingEnabled(): Boolean {
        return false
    }

    /**
     * 根据设备内存情况动态计算并发数
     * 低端机 (<= 4GB RAM): 限制为 5,防止 OOM 和 CPU 抢占导致 UI 卡顿
     * 高端机 (> 4GB RAM): 开启 6+,追求极致加载速度
     */
    private fun getConfig(context: Context): Config {
        val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as? android.app.ActivityManager
        // 获取总内存
        val memInfo = android.app.ActivityManager.MemoryInfo()
        activityManager?.getMemoryInfo(memInfo)

        // 4GB = 4 * 1024 * 1024 * 1024L
        val threshold = 4L * 1024 * 1024 * 1024L

        // 动态计算最佳线程数 (策略:CPU核心数 + 1,但限制在 6~10 之间) ---
        val cpuCount = Runtime.getRuntime().availableProcessors()
        // 比如:
        // 4核手机 -> max(6, 5) = 6 个线程
        // 8核手机 -> min(10, 9) = 9 个线程
        val calculatedThreads = min(10, max(6, cpuCount + 1))

        return if (memInfo.totalMem > threshold) {
            Config(
                glideThreadCount = calculatedThreads,
                maxRequestsPerHost = 15,
                maxIdleConnections = 10
            )
        } else {
            Config(
                glideThreadCount = calculatedThreads,
                maxRequestsPerHost = 10,
                maxIdleConnections = 5
            )
        }
    }

    private data class Config(
        val glideThreadCount: Int,
        val maxRequestsPerHost: Int,
        val maxIdleConnections: Int
    )
}