Glide弱网环境无法加载本地图片的问题

1,950 阅读1分钟

先说下我出现此问题的场景:图片列表中有部分本地图片,其余都是网络图片。在弱网环境下,期望本地图片先展示出来,而实际本地图片不一定能展示出来。

原因分析: Glide内部Decode是有个线程池的,在执行的时候会将任务丢掉线程池中(EngineJob.java):

  public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }
  private GlideExecutor getActiveSourceExecutor() {
    return useUnlimitedSourceGeneratorPool
        ? sourceUnlimitedExecutor : (useAnimationPool ? animationExecutor : sourceExecutor);
  }

默认情况下,都用的是sourceExecutor,其在GlideBuilder中定义:

  Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }
    // 省略剩余代码
  }
  public static GlideExecutor newSourceExecutor() {
    return newSourceExecutor(
        calculateBestThreadCount(),
        DEFAULT_SOURCE_EXECUTOR_NAME,
        UncaughtThrowableStrategy.DEFAULT);
  }
  public static int calculateBestThreadCount() {
    if (bestThreadCount == 0) {
      bestThreadCount =
          Math.min(MAXIMUM_AUTOMATIC_THREAD_COUNT, RuntimeCompat.availableProcessors());
    }
    return bestThreadCount;
  }

故可以看出,线程池最多执行4个任务,故在弱网清空下,若先加入的是网络任务,则在线程池满了的时候,新的请求会处于阻塞状态,从而造成本地图片请求不执行的问题。

注意看getActiveSourceExecutor方法,其中有个useUnlimitedSourceGeneratorPool变量,用的线程池构造代码如下:

  public static GlideExecutor newUnlimitedSourceExecutor() {
    return new GlideExecutor(new ThreadPoolExecutor(
        0,
        Integer.MAX_VALUE,
        KEEP_ALIVE_TIME_MS,
        TimeUnit.MILLISECONDS,
        new SynchronousQueue<Runnable>(),
        new DefaultThreadFactory(
            SOURCE_UNLIMITED_EXECUTOR_NAME,
            UncaughtThrowableStrategy.DEFAULT,
            false)));
  }

故若使用此线程池,那么就不会受影响,也就能解决问题了,最终代码如下:

    RequestOptions options = new RequestOptions();
    options.useUnlimitedSourceGeneratorsPool(true);
    final GlideRequest<Bitmap> req = GlideApp.with(App.getInstance())
        .asBitmap()
        .load(img)
        .apply(options);