Android面试题经典之Glide取消加载以及线程池优化

简介: Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

Glide通过生命周期取消加载

生命周期回调过程
onStop
--->RequestManager.onStop
-->RequestTracker.pauseRequest
--> SingleRequest.pause
--> SingleRequest.cancel
---> Engine.cancel
---> EngineJob.removeCallback
---> 如果所有的回调监听都移除了
--> DecodeJob.cancel

//EngineJob.class
synchronized void removeCallback(ResourceCallback cb) {
   
   stateVerifier.throwIfRecycled();
   cbs.remove(cb);
   if (cbs.isEmpty()) {
   
     cancel();
     boolean isFinishedRunning = hasResource || hasLoadFailed;
     if (isFinishedRunning && pendingCallbacks.get() == 0) {
   
       release();
     }
   }
}
  • 如果任务没有执行,就从队列里移除,取消任务
  • 如果任务已经执行,就利用isCancelled标记在停止流程
//DecodeJob.class
public void cancel() {
   
      isCancelled = true;
      DataFetcherGenerator local = currentGenerator;
      if (local != null) {
   
          local.cancel();
      }
}

上面最终会调用到具体的获取图片的任务,比如从网络获取图片的HttpUrlFetcher

 //HttpUrlFetcher.class
private volatile boolean isCancelled;
@Override
public void cancel() {
   
    // TODO: we should consider disconnecting the url connection here, but we can't do so
    // directly because cancel is often called on the main thread.
    isCancelled = true;
}

//内部是通过HttpURLConnection来从网络获取数据
private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException {
   
    ...

    urlConnection = buildAndConfigureConnection(url, headers);

    try {
   
      // Connect explicitly to avoid errors in decoders if connection fails.
      urlConnection.connect();
      // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
      stream = urlConnection.getInputStream();
    } catch (IOException e) {
   
      ...
    }

    if (isCancelled) {
   
      return null;
    }

    final int statusCode = getHttpStatusCodeOrInvalid(urlConnection);
    if (isHttpOk(statusCode)) {
   
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
   
      String redirectUrlString = urlConnection.getHeaderField(REDIRECT_HEADER_FIELD);
      ...
      cleanup();
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == INVALID_STATUS_CODE) {
   
      throw new HttpException(statusCode);
    } else {
   
      ...
    }
}

由于cancel方法一般是在主线程调用的,所以这里采用的是volatile关键字这种方式,在正式获取网络数据时会进行拦截;

  • 如果拦截到了,那直接返回null;如果没拦截到,就获取到数据
  • 以上最终都会回调到DecodeJob的onDataFetcherReady方法

onDataFetcherReady ---> decodeFromRetrievedData ---> decodeFromData

private void decodeFromRetrievedData() {
   
     ...
     Resource<R> resource = null;
     try {
   
       resource = decodeFromData(currentFetcher, currentData, currentDataSource);
     } catch (GlideException e) {
   
       ...
     }
     if (resource != null) {
   
       notifyEncodeAndRelease(resource, currentDataSource, isLoadingFromAlternateCacheKey);
     } else {
   
       //任务被拦截,尝试其他的加载方式
       runGenerators();
     }
}

decodeFromData中会进行判断,如果data为Null就直接返回Null(被拦截时会是null),这个时候会执行runGenerators方法

runGenerators方法实际上就是加载流程的流转,比如先从文件中加载,文件中没有,就去网络加载,一个个去试这样。当然这里面肯定也有cancel拦截的

private void runGenerators() {
   
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;

    //被cancel拦截就不会尝试其他加载方式,直接任务取消

    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
   
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
   
        reschedule();
        return;
      }
    }
    // We've run out of stages and generators, give up.
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
   
      notifyFailed();
    }
}

所以当加载数据的流程被拦截了,比如网络请求返回null,那到这里这个流程就拦截下来了,直接

notifyFailed任务失败了。

那如果网络加载的时候没有拦截住呢?data就不会为null,就会走notifyEncodeAndRelease方法,最终会一直走到EngineJob的notifyCallbacksOfResult方法,这个方法里面又会有cancel拦截。这样也就是数据加载前加载后都被拦截下来了

Glide中的线程池

自定义ThreadFactory,主要的一个功能是实现限制部分线程网络访问,利用的是严苛模式

@Override
public Thread newThread(@NonNull final Runnable runnable) {
   
   Thread newThread =
       delegate.newThread(
           new Runnable() {
   
             @Override
             public void run() {
   
               if (preventNetworkOperations) {
   
                 StrictMode.setThreadPolicy(
                     new ThreadPolicy.Builder().detectNetwork().penaltyDeath().build());
               }
               try {
   
                 runnable.run();
               } catch (Throwable t) {
   
                 uncaughtThrowableStrategy.handle(t);
               }
             }
           });
   newThread.setName("glide-" + name + "-thread-" + threadNum.getAndIncrement());
   return newThread;
}

线程池主要有这几种:

  • AnimationExecutor:加载动画相关,禁止访问网络;如果CPU核心数大于4,就是2个线程,否则是一个线程,核心线程数和最大线程数相同

  • diskCacheExecutor:从磁盘加载图片,禁止访问网络;线程数为1,核心线程数和最大线程数相同

  • sourceExecutor:可以访问网络,线程数跟CPU核心数有关,不大于4,核心线程数和最大线程数相同

  • newUnlimitedSourceExecutor:用于网络请求图片,没有核心线程,只有非核心线程,类似CacheThreadPoll

Glide做了线程池优化,核心线程也会遵循超时策略

public GlideExecutor build() {
   
  if (TextUtils.isEmpty(name)) {
   
    throw new IllegalArgumentException(
        "Name must be non-null and non-empty, but given: " + name);
  }
  ThreadPoolExecutor executor =
      new ThreadPoolExecutor(
          corePoolSize,
          maximumPoolSize,
          /*keepAliveTime=*/ threadTimeoutMillis,
          TimeUnit.MILLISECONDS,
          new PriorityBlockingQueue<Runnable>(),
          new DefaultThreadFactory(
              threadFactory, name, uncaughtThrowableStrategy, preventNetworkOperations));

  if (threadTimeoutMillis != NO_THREAD_TIMEOUT) {
   
    executor.allowCoreThreadTimeOut(true);
  }

  return new GlideExecutor(executor);
}

欢迎关注我的公众号AntDream查看更多精彩文章!

目录
相关文章
|
7天前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
76 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
1月前
|
存储 消息中间件 人工智能
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
154 10
【08】AI辅助编程完整的安卓二次商业实战-修改消息聊天框背景色-触发聊天让程序异常终止bug牵涉更多聊天消息发送优化处理-优雅草卓伊凡
|
1月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
|
4月前
|
数据采集 存储 Web App开发
多线程爬虫优化:快速爬取并写入CSV
多线程爬虫优化:快速爬取并写入CSV
|
7月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
1635 77
|
5月前
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
208 1
|
4月前
|
机器学习/深度学习 监控 算法
局域网行为监控软件 C# 多线程数据包捕获算法:基于 KMP 模式匹配的内容分析优化方案探索
本文探讨了一种结合KMP算法的多线程数据包捕获与分析方案,用于局域网行为监控。通过C#实现,该系统可高效检测敏感内容、管理URL访问、分析协议及审计日志。实验表明,相较于传统算法,KMP在处理大规模网络流量时效率显著提升。未来可在算法优化、多模式匹配及机器学习等领域进一步研究。
135 0
|
9月前
|
监控 Kubernetes Java
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
本文由40岁老架构师尼恩撰写,针对一线互联网企业的高频面试题“如何确定系统的最佳线程数”进行系统化梳理。文章详细介绍了线程池设计的三个核心步骤:理论预估、压测验证和监控调整,并结合实际案例(5000qps、500ms响应时间、4核8G机器)给出具体参数设置建议。此外,还提供了《尼恩Java面试宝典PDF》等资源,帮助读者提升技术能力,顺利通过大厂面试。关注【技术自由圈】公众号,回复“领电子书”获取更多学习资料。
|
6月前
|
数据采集 存储 网络协议
Java HttpClient 多线程爬虫优化方案
Java HttpClient 多线程爬虫优化方案
|
9月前
|
编译器 Android开发 开发者
Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
Lambda表达式和匿名函数都是Kotlin中强大的特性,帮助开发者编写简洁而高效的代码。理解它们的区别和适用场景,有助于选择最合适的方式来解决问题。希望本文的详细讲解和示例能够帮助你在Kotlin开发中更好地运用这些特性。
186 9

热门文章

最新文章