胖虎谈ImageLoader框架(三)

2024-05-31 03:48

本文主要是介绍胖虎谈ImageLoader框架(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

从学校出来的这半年时间,发现很少有时间可以静下来学习和写博文了,为了保持着学习和分享的习惯,我准备每周抽出一部分时间为大家带来一个优秀的Android框架源码阅读后的理解系列博文。

期许:希望可以和大家一起学习好此框架,也希望大家看博文前最好是先了解下框架的基本使用场景和使用方法,有什么问题可以留言给我,交流学习。
当然,再好的博文,也不如自己看一遍源码!


这周为大家带来的是《胖虎谈ImageLoader框架》系列,分析优秀的框架源码能让我们更迅速地提升,大家共勉!!
源码包下载地址:http://download.csdn.net/detail/u011133213/9210765

希望我们尊重每个人的成果,转载请注明出处。
转载于:CSDN 胖虎 , http://blog.csdn.net/ljphhj


正文

继上2篇博文《胖虎谈ImageLoader框架(一)》 《胖虎谈ImageLoader框架(二)》
带来这篇《胖虎谈ImageLoader框架(三)》,上篇我们提到的几个涉及到的类,希望读者可以自己去阅读源码理解,此篇博文不希望在解释源码,希望提到一些那些类中涉及到的知识(线程池,下载器实现,ReentrantLock和Synchronized,Collections.synchronizedMap等)

(ps:读此博文前,希望网友已经阅读并理解了《胖虎谈ImageLoader框架(一)》 《胖虎谈ImageLoader框架(二)》再阅读此博文。)

1、Java线程池
1.1 什么情况下我们才使用线程池?
答:需要做大量的请求,并且每个请求的时间很短。

1.2 使用线程池的好处?
答:减少频繁建立和销毁线程对象所需时间和内存消耗,提升了效率。

1.3 开始学习Java中的线程池
(1) JAVA中线程池的类和继承实现关系UML图
这里写图片描述

(2) ThreadPoolExecutor / ScheduledThreadPoolExecutor

2.1 ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

corePoolSize: 核心线程数量
maximumPoolSize: 线程池中最大可容纳数量
keepAliveTime: 线程在队列中等待被执行的超时时间
unit: 线程池允许超时时间的单位
workQueue: 线程池采用的缓冲队列
threadFactory:创建线程的工厂类
handler: 拒绝线程任务的处理类

线程池的运行机制:

  1. 调用execute(Runnable)方法,添加一个线程任务到线程池中。
  2. ▲线程池判断当前池中存在线程数 < corePoolSize, 立即创建一个新的线程,并执行该Runnable对象的run()方法。▲如果>=corePoolSize, 会将该任务添加到workQueue队列中,等待执行。▲如果workQueue队列中已经满了,并且线程池中的线程数还 < maximumPoolSize, 那么会创建一个新的线程来放入线程池中来处理此任务。▲如果如果workQueue队列中已经满了,并且线程池中的线程数>=maximumPoolSize , 那么会调用handler的策略方法拒绝掉该任务。

学习这个类,主要还是学习一下这个类的参数的意义和运行的机制,当然咱们也要顺带把这个类里面涉及到的周边类也学习一下。这里面提到了 ThreadFactory(可以自定义一个,用来修改线程的name, group, priority, daemon status等) , 队列(SynchronousQueue、LinkedBlockingQueue、ArrayBlockingQueue),拒绝任务的策略种类(1. AbortPolicy[直接抛RejectedExecutionException异常]、2.CallerRunsPolicy[再给一次尝试的机会]、3.DiscardPolicy[无作为]、4.DiscardOldestPolicy[舍弃队头任务,再尝试添加当前任务])

2.2 ScheduledThreadPoolExecutor
这个类继承于ThreadPoolExecutor,所以父类有的,它也一样,它的使用方式是 :
schedule(Runnable command, long delay, TimeUnit unit) , 可以设定一个延时执行的任务。

2、下载器实现

  1. ImageLoader中实现了三种的下载器:BaseImageDownloader、NetworkDeniedImageDownloader、SlowNetworkImageDownloader(都实现了接口ImageDownloader)
  2. ImageDownloader接口中,实现了Scheme类,用于判断传入的一个Uri是什么Schme和其他操作。
    Scheme分为:HTTP(“http”), HTTPS(“https”), FILE(“file”), CONTENT(“content”), ASSETS(“assets”), DRAWABLE(“drawable”), UNKNOWN("")。
    3.▲NetworkDeniedImageDownloader下载器,因为网络不能接触,所以就不处理"http"和"https" 这两种需要网络的Scheme。
private static class NetworkDeniedImageDownloader implements ImageDownloader {private final ImageDownloader wrappedDownloader;public NetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {this.wrappedDownloader = wrappedDownloader;}@Overridepublic InputStream getStream(String imageUri, Object extra) throws IOException {switch (Scheme.ofUri(imageUri)) {case HTTP:case HTTPS:throw new IllegalStateException();default:return wrappedDownloader.getStream(imageUri, extra);}}}

▲SlowNetworkImageDownloader下载器, 考虑到网络情况是属于比较差的,所以需要用到的InputStream来处理Scheme为"http"和"https"的Uri。

private static class SlowNetworkImageDownloader implements ImageDownloader {private final ImageDownloader wrappedDownloader;public SlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {this.wrappedDownloader = wrappedDownloader;}@Overridepublic InputStream getStream(String imageUri, Object extra) throws IOException {InputStream imageStream = wrappedDownloader.getStream(imageUri, extra);switch (Scheme.ofUri(imageUri)) {case HTTP:case HTTPS:return new FlushedInputStream(imageStream);default:return imageStream;}}}

BaseImageDownloader:此下载器最为重要,这个类里面写了ImageLoader处理各种数据源时是如何下载图片资源的。这边分别对所有的Scheme将对应的处理函数贴出来,有兴趣的网友再自行去看哈。这个其实可以抽出来作为自己的一个图片下载类,因为所有不同来源的图片下载方式都有。

	@Overridepublic InputStream getStream(String imageUri, Object extra) throws IOException {switch (Scheme.ofUri(imageUri)) {case HTTP:case HTTPS:return getStreamFromNetwork(imageUri, extra);case FILE:return getStreamFromFile(imageUri, extra);case CONTENT:return getStreamFromContent(imageUri, extra);case ASSETS:return getStreamFromAssets(imageUri, extra);case DRAWABLE:return getStreamFromDrawable(imageUri, extra);case UNKNOWN:default:return getStreamFromOtherSource(imageUri, extra);}}

网络图片,Http和Https的下载处理:

protected HttpURLConnection createConnection(String url, Object extra) throws IOException {String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS);HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection();conn.setConnectTimeout(connectTimeout);conn.setReadTimeout(readTimeout);return conn;}protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {HttpURLConnection conn = createConnection(imageUri, extra);int redirectCount = 0;while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {conn = createConnection(conn.getHeaderField("Location"), extra);redirectCount++;}InputStream imageStream;try {imageStream = conn.getInputStream();} catch (IOException e) {// Read all data to allow reuse connection (http://bit.ly/1ad35PY)IoUtils.readAndCloseStream(conn.getErrorStream());throw e;}if (!shouldBeProcessed(conn)) {IoUtils.closeSilently(imageStream);throw new IOException("Image request failed with response code " + conn.getResponseCode());}return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength());}

来自本地文件,Scheme为"file"的下载处理:

protected InputStream getStreamFromFile(String imageUri, Object extra) throws IOException {String filePath = Scheme.FILE.crop(imageUri);if (isVideoFileUri(imageUri)) {return getVideoThumbnailStream(filePath);} else {BufferedInputStream imageStream = new BufferedInputStream(new FileInputStream(filePath), BUFFER_SIZE);return new ContentLengthInputStream(imageStream, (int) new File(filePath).length());}}@TargetApi(Build.VERSION_CODES.FROYO)private InputStream getVideoThumbnailStream(String filePath) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(filePath, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND);if (bitmap != null) {ByteArrayOutputStream bos = new ByteArrayOutputStream();bitmap.compress(CompressFormat.PNG, 0, bos);return new ByteArrayInputStream(bos.toByteArray());}}return null;}

来自ContentPorivder传入的Scheme为"content"的下载处理:

protected InputStream getStreamFromContent(String imageUri, Object extra) throws FileNotFoundException {ContentResolver res = context.getContentResolver();Uri uri = Uri.parse(imageUri);if (isVideoContentUri(uri)) { // video thumbnailLong origId = Long.valueOf(uri.getLastPathSegment());Bitmap bitmap = MediaStore.Video.Thumbnails.getThumbnail(res, origId, MediaStore.Images.Thumbnails.MINI_KIND, null);if (bitmap != null) {ByteArrayOutputStream bos = new ByteArrayOutputStream();bitmap.compress(CompressFormat.PNG, 0, bos);return new ByteArrayInputStream(bos.toByteArray());}} else if (imageUri.startsWith(CONTENT_CONTACTS_URI_PREFIX)) { // contacts photoreturn ContactsContract.Contacts.openContactPhotoInputStream(res, uri);}return res.openInputStream(uri);}

来自Assets和Drawable中传入的Scheme为"assets"和"drawable"的下载处理:

	protected InputStream getStreamFromAssets(String imageUri, Object extra) throws IOException {String filePath = Scheme.ASSETS.crop(imageUri);return context.getAssets().open(filePath);}protected InputStream getStreamFromDrawable(String imageUri, Object extra) {String drawableIdString = Scheme.DRAWABLE.crop(imageUri);int drawableId = Integer.parseInt(drawableIdString);return context.getResources().openRawResource(drawableId);}

**3、ReentrantLock和Synchronized **
这两个的比较,我查阅了一下网上的文章,本想自己做一些理解和总结,看了一篇文章觉得剖析得非常好,偷懒直接贴上链接地址,如果您对此知识还不是完全熟悉,那么推荐您也可以看看。(http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html)

4、Collections.synchronizedMap类(线程安全)
此Map用于可能多线程共享使用的情况。源码如下,无非就是将自身作为一个互斥量,进行Map的各种操作时用synchronized关键字将其锁住,保证线程安全。

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {return new SynchronizedMap<>(m);}/*** @serial include*/private static class SynchronizedMap<K,V>implements Map<K,V>, Serializable {private static final long serialVersionUID = 1978198479659022715L;private final Map<K,V> m;     // Backing Mapfinal Object      mutex;        // Object on which to synchronizeSynchronizedMap(Map<K,V> m) {this.m = Objects.requireNonNull(m);mutex = this;}SynchronizedMap(Map<K,V> m, Object mutex) {this.m = m;this.mutex = mutex;}public int size() {synchronized (mutex) {return m.size();}}public boolean isEmpty() {synchronized (mutex) {return m.isEmpty();}}public boolean containsKey(Object key) {synchronized (mutex) {return m.containsKey(key);}}public boolean containsValue(Object value) {synchronized (mutex) {return m.containsValue(value);}}public V get(Object key) {synchronized (mutex) {return m.get(key);}}public V put(K key, V value) {synchronized (mutex) {return m.put(key, value);}}public V remove(Object key) {synchronized (mutex) {return m.remove(key);}}public void putAll(Map<? extends K, ? extends V> map) {synchronized (mutex) {m.putAll(map);}}public void clear() {synchronized (mutex) {m.clear();}}private transient Set<K> keySet;private transient Set<Map.Entry<K,V>> entrySet;private transient Collection<V> values;public Set<K> keySet() {synchronized (mutex) {if (keySet==null)keySet = new SynchronizedSet<>(m.keySet(), mutex);return keySet;}}public Set<Map.Entry<K,V>> entrySet() {synchronized (mutex) {if (entrySet==null)entrySet = new SynchronizedSet<>(m.entrySet(), mutex);return entrySet;}}public Collection<V> values() {synchronized (mutex) {if (values==null)values = new SynchronizedCollection<>(m.values(), mutex);return values;}}public boolean equals(Object o) {if (this == o)return true;synchronized (mutex) {return m.equals(o);}}public int hashCode() {synchronized (mutex) {return m.hashCode();}}public String toString() {synchronized (mutex) {return m.toString();}}// Override default methods in Map@Overridepublic V getOrDefault(Object k, V defaultValue) {synchronized (mutex) {return m.getOrDefault(k, defaultValue);}}@Overridepublic void forEach(BiConsumer<? super K, ? super V> action) {synchronized (mutex) {m.forEach(action);}}@Overridepublic void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {synchronized (mutex) {m.replaceAll(function);}}@Overridepublic V putIfAbsent(K key, V value) {synchronized (mutex) {return m.putIfAbsent(key, value);}}@Overridepublic boolean remove(Object key, Object value) {synchronized (mutex) {return m.remove(key, value);}}@Overridepublic boolean replace(K key, V oldValue, V newValue) {synchronized (mutex) {return m.replace(key, oldValue, newValue);}}@Overridepublic V replace(K key, V value) {synchronized (mutex) {return m.replace(key, value);}}@Overridepublic V computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction) {synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}}@Overridepublic V computeIfPresent(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction) {synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}}@Overridepublic V compute(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction) {synchronized (mutex) {return m.compute(key, remappingFunction);}}@Overridepublic V merge(K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction) {synchronized (mutex) {return m.merge(key, value, remappingFunction);}}private void writeObject(ObjectOutputStream s) throws IOException {synchronized (mutex) {s.defaultWriteObject();}}}

总结

其实这篇博文旨在将一些框架中引用到的知识点,可是平时可能被我忽视的或者少用到的,进行记录,方便我自身充电,与其说是在写博文交流,不如说是自身的补缺补漏,大牛们可以无视O(∩_∩)O!

在这里插入图片描述

这篇关于胖虎谈ImageLoader框架(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1017342

相关文章

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

数据治理框架-ISO数据治理标准

引言 "数据治理"并不是一个新的概念,国内外有很多组织专注于数据治理理论和实践的研究。目前国际上,主要的数据治理框架有ISO数据治理标准、GDI数据治理框架、DAMA数据治理管理框架等。 ISO数据治理标准 改标准阐述了数据治理的标准、基本原则和数据治理模型,是一套完整的数据治理方法论。 ISO/IEC 38505标准的数据治理方法论的核心内容如下: 数据治理的目标:促进组织高效、合理地

ZooKeeper 中的 Curator 框架解析

Apache ZooKeeper 是一个为分布式应用提供一致性服务的软件。它提供了诸如配置管理、分布式同步、组服务等功能。在使用 ZooKeeper 时,Curator 是一个非常流行的客户端库,它简化了 ZooKeeper 的使用,提供了高级的抽象和丰富的工具。本文将详细介绍 Curator 框架,包括它的设计哲学、核心组件以及如何使用 Curator 来简化 ZooKeeper 的操作。 1

【Kubernetes】K8s 的安全框架和用户认证

K8s 的安全框架和用户认证 1.Kubernetes 的安全框架1.1 认证:Authentication1.2 鉴权:Authorization1.3 准入控制:Admission Control 2.Kubernetes 的用户认证2.1 Kubernetes 的用户认证方式2.2 配置 Kubernetes 集群使用密码认证 Kubernetes 作为一个分布式的虚拟

Spring Framework系统框架

序号表示的是学习顺序 IoC(控制反转)/DI(依赖注入): ioc:思想上是控制反转,spring提供了一个容器,称为IOC容器,用它来充当IOC思想中的外部。 我的理解就是spring把这些对象集中管理,放在容器中,这个容器就叫Ioc这些对象统称为Bean 用对象的时候不用new,直接外部提供(bean) 当外部的对象有关系的时候,IOC给它俩绑好(DI) DI和IO

Sentinel 高可用流量管理框架

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。 Sentinel 具有以下特性: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应

利用Django框架快速构建Web应用:从零到上线

随着互联网的发展,Web应用的需求日益增长,而Django作为一个高级的Python Web框架,以其强大的功能和灵活的架构,成为了众多开发者的选择。本文将指导你如何从零开始使用Django框架构建一个简单的Web应用,并将其部署到线上,让世界看到你的作品。 Django简介 Django是由Adrian Holovaty和Simon Willison于2005年开发的一个开源框架,旨在简

Yii框架relations的使用

通过在 relations() 中声明这些相关对象,我们就可以利用强大的 Relational ActiveRecord (RAR) 功能来访问资讯的相关对象,例如它的作者和评论。不需要自己写复杂的 SQL JOIN 语句。 前提条件 在组织数据库时,需要使用主键与外键约束才能使用ActiveReocrd的关系操作; 场景 申明关系 两张表之间的关系无非三种:一对多;一对一;多对多; 在

laravel框架实现redis分布式集群原理

在app/config/database.php中配置如下: 'redis' => array('cluster' => true,'default' => array('host' => '172.21.107.247','port' => 6379,),'redis1' => array('host' => '172.21.107.248','port' => 6379,),) 其中cl