-
将固态作为机械硬盘缓存工具,类似Intel快速储存驱动
2018-05-19 00:24:39此工具可以将固态硬盘或内存作为机械硬盘的缓存,从而提升固态硬盘响应速度,绿色无毒,亲测可用, -
Android工具封装之三级缓存加载图片
2018-04-19 18:47:23通过简单的封装了LruCache内存缓存 + DiskLruCache硬盘缓存 + HttpUrl网络请求来实现三级缓存。该封装适合ListView,GirdView等ViewGroup这类的容器,并且在对应的ImageView中用对应图片的Url作为Tag,以防止在异步...参考郭霖的文章 点击打开链接写了下郭霖的三级缓存加载图片的照片墙之后打算封装个三级缓存加载图片以便以后开发使用。通过简单的封装了LruCache内存缓存 + DiskLruCache硬盘缓存 + HttpUrl网络请求来实现三级缓存。
该封装适合ListView,GirdView等ViewGroup这类的容器,并且在对应的ImageView中用对应图片的Url作为Tag,以防止在异步加载图片使用产生图片位置错乱。
使用方法:
1.新建实例:构造函数:ImageLoadUtil(Context context, String cacheFileName, T viewGroup)
cacheFileName:缓存的目录的名字
viewGroup: 父容器,ListView,Girdview等。
2.获取图片并设置到对应的view:方法:getBitmapForUtil(ImageView imageView, String imageUrl)
imageView:带Url作为Tag的ImageView
imageUrl:图片下载地址
3.清理:
取消所有正在下载或等待下载的任务:void cancelAllTasks()将缓存记录同步到journal文件中:void fluchCache()
源码地址:工具下载
-
ssd检测坏块工具_2020年SSD固态硬盘推荐选购技巧(12月更新)
2020-12-17 00:11:47目录本文目录结构如下:目录一、固态硬盘与机械硬盘区别固态硬盘与机械硬盘区别二、固态硬盘原理1、组成固态硬盘是一种以闪存...缓存:由于硬盘与内存的读写速度差别巨大,而应用程序数据往往需要从硬盘加载到内存...目录
本文目录结构如下:
目录 一、固态硬盘与机械硬盘区别
固态硬盘与机械硬盘区别 二、固态硬盘原理
1、组成
固态硬盘是一种以闪存(NAND Flash)作为存储介质的存储设备。主要由闪存芯片、缓存、主控、接口组成。如下图所示:
固态硬盘组成 - 闪存芯片:主要用来存储数据,又可分为SLC、MLC、TLC、QLC,后文会介绍几种芯片的区别。
- 缓存:由于硬盘与内存的读写速度差别巨大,而应用程序数据往往需要从硬盘加载到内存中进行操作。增加缓存的目的就是为了减少两者的速度差所带来的操作上的等待。
- 主控:主要用来管理以及维护固态硬盘的使用。主要功能有磨损平衡、坏块管理、垃圾回收、预留空间、ECC、断电保护、加密等。后文做主要介绍。
- 接口:常见的有M2,SATA;其它的还有PCIE、mSATA、ZIF等,以适配不同的硬件产品。目前市面上常见的为前面两种。
2、读写过程
固态硬盘的读写操作不同于机械硬盘,机械硬盘的读写操作使用的是机械臂,而固态硬盘则是通过主控对闪存颗粒充放电进行读写。
主控对闪存颗粒进行充电
依据充电的电压标识数据
若需要重新写入,需要先擦除数据。3、主控功能
- 磨损平衡磨损平衡的主要目的是使得每个数据块的擦写次数尽可能的相同。
在日常的使用中,某些区域我们可能会频繁地写入数据,而有些区域的数据却不怎么更新。这就导致了使用频繁的区域磨损严重,加快了该区域的存储介质的损坏。磨损平衡就是为了解决这一问题而产生。
磨损平衡又可以分为以下两种:- 动态磨损平衡:只有被更新的文件所占用的物理页被磨损平衡。
- 静态磨损平衡:在动态磨损算法的基础上,增加了对那些不常用文件占用的物理页进行磨损平衡、
- 垃圾回收
磨损平衡的执行需要又足够的未使用空间来写入更新后的数据,当可用的空间低于一个阈值后,主控就会将那些零散的数据整理起来合并写到新的空白快中,然后擦除这个块以增加可用空间。如下图所示:
垃圾回收示意图 - 坏块管理
坏块就是存储介质中包含了不稳定的地址,不能保证读写的可靠性。
当有坏块时,会在坏块的第一页的SA区打上标记,这样坏块管理软件就能依靠SA扇区标记制作坏块表。
SA区指页中的第4096~4319区域,用户不能访问,主要用来存放坏块信息、ECC算法、文件系统等。
SA扇区示意图 - 预留空间
- 预留空间对用户不可见,一般用来处理磨损平衡,ECC和坏块映射表。
- ECC(Error Correcting Code)
- 存储领域要求错误码率不小于10^-9,直接读取的错误码率无法达到这个要求,所以引入了纠错码。
- 一般情况下主控或者驱动会检查闪存区域,尽量保证在出现不可纠正的错误前将该闪存作为坏块屏蔽。
- 不同闪存颗粒要求的ECC不同,不同主控支持的ECC能力也不同,一般,主控越好,ECC能力越强。
三、闪存架构
SSD的基本存储单元分为以下四类:
固态硬盘闪存架构 1、单阶存储单元(Single-Level Cell,SLC)
SLC闪存每个存储单元存储1bit信息,可以表示0或1。
低电位:表示0高电位:表示1
优点:速度快、功耗低、存储单元寿命更长。
缺点:成本高,容量小。
2、多阶存储单元(Multi-Level Cell,MLC)
MLC闪存每个存储单元存储2bits信息,可以表示00、01、10、11。其中的多阶(Multi)指充电的电压标识有多个。
用低电位、次低电位、次高电位、高电位分别表示00、01、10、11。
相比SLC,由于一个单元可存储2bit,其生产成本降低,价格更便宜,容量也有所提高,但其传输速度较慢,功耗较高,存储单元寿命较短。
3、三阶储存单元(Triple-Level Cell, TLC)
TLC闪存每个存储单元存储3bits信息,可以表示000、001、······、110、111共八种组合。
需要注意的是,有些地方也把TLC称为3-bit MLC。
用八个阶段电位表示八种不同的比特信息。
相比MLC,由于一个单元可存储更多的bit,其生产成本降低,价格更便宜,容量也有所提高,但其传输速度较慢,功耗较高,存储单元寿命较短。
4、四阶储存单元(Quad-Level Cell, QLC)
QLC闪存每个存储单元存储4bits信息,可以表示0000、0001、······、1110、1111共16种组合。
将电位划分更细来表示更多的信息。
容量大,价格便宜。但于此同时,其功耗最高,寿命最短。
5、3D NAND
3D NAND是一种扩容技术,当平面NAND(Planar NAND)发展到一定时候 ,就会受到容量的限制,在固定的平面上无法安放更多的闪存芯片时,将平面NAND堆叠起来,组成3D NAND以增加容量。
3D NAND 5、区别
下表列出了四种闪存的区别:
各种闪存架构区别 四、接口
固态硬盘接口众多,有SATA、PCI Express、mSATA、M.2、ZIF、IDE、U.2、CF、CFast等不同的接口,本文主要就常见的SATA以及M.2接口进行介绍。
1、SATA
串行ATA(英语:Serial ATA,全称:Serial Advanced Technology Attachment),SATA接口最早出现在2003,为SATA 1.0,在2004年又出现了SATA 2.0,2009年推出SATA 3.0,随后又发布了SATA 3.1、SATA 3.2、SATA 3.3接口。下表给出不同版本的SATA接口速率比较:
各版本SATA接口 目前常见的SATA接口多为SATA3,如下图所示:
SATA3 SATA3接口的固态带宽可达6Gb/s,即理论速度600MB/s。
2、M.2
M.2是由是由 PCI-SIG 和 SATA-IO 标准组织所开发,原名为NGFF (Next Generation Form Factor),2013年正式命名为M.2。
M.2协议广泛涵盖了PCIe、SATA、USB等接口,即原本采用PCIe、SATA、USB等接口的介质,都可以依照NGFF的外形尺寸规范以及脚针定义来加以重新设计,从而变为采用M.2接口的设备。
M.2示意 此外,考虑到PCIe、SATA、USB等不同接口的脚针存在差异,因此,M.2/NGFF为此定制了多组防呆位置来避免混乱或误插。目前在使用的有A/B/E/M key。
M.2模块防呆键位和提供的接口如下
M.2防呆接口 M.2防呆key位置 由上表可以看出,目前用于SSD的主要为B key 及 M key两种类型。下面 主要介绍这两种应用于SSD的插槽类型。
3、M.2 SDD两种主要插槽类型(B key 及 M key)
目前市场上的产品中,M.2固态主要有两种插槽类型:B key(socket 2)以及 M key(socket 3),B key的防呆位于左边(12 - 19针,6 pin),M key位于右边(59 - 66针,5 pin)。如下图所示:
B key & M key 两种接口的协议类型以及速度如下:
- B key(socket 2),PCIe×2或SATA协议
- 走PCIe×2:不超过1000Mb/s
- 走SATA:不超过550Mb/s
- M key(socket 3),PCIe×4协议
- 不支持NVME:1500Mb/s
- 支持NVME:超过2000Mb/s
4、M.2 SDD两种主要脚位类型(B+M key 及 M key)
当你对上面的内容有了了解后,你信誓旦旦地去选择SSD,你很快就会发现另外一个问题,市面上的固态并非一个萝卜一个坑地对应着,而是具有两个防呆缺口的B+M key型式以及只有一个防呆缺口的M key 型式。这是因为M.2 SSD 产品为了能同时兼容于两种插槽,便把金手指的部分设计成 B+M Key 的形式,如下图所示:
固态硬盘接口示意 两种插槽对应两种脚位类型,共有四种组合。对B key来说,B+M key的SSD可以顺利插入,而M key的脚位却无法插入。
B key插槽 对于B key这种类型的插槽,如果你的主板支持PCIe×2的话,那么你可以获得不超过1000Mb/s的传输速度;如果仅支持SATA协议的话,那么你的速度将不超过550Mb/s。
对M key来说,无论是B+M key或是M key的SSD都可以插入。
M key插槽 对于M key来说,走的是PCIe×4,如果主板支持NVME协议的话,可以获得超过2000Mb/s的传输速度。如果不支持NVME的话,只能获得1500Mb/s的传输速度。
5、能插进去未必能正常使用
SSD能插进去不代表就能正常使用。比如某些主板的M.2插槽仅支持PCIe通道,那么SATA 的M.2 SSD就不能正常使用,这个需要具体查看主板说明文档。还有,如果你的固态是走SATA 通道的M.2 SSD,同样会受到6Gb/s 带宽的限制,性能等同于2.5寸的SATA SSD。
五、品牌
自主生产闪存颗粒(推荐指数:★★★★★)
部分自主生产闪存芯片厂商 - 三星
- 因特尔
- 美光
- 闪迪
- 东芝
- 海力士
- 英飞凌
这些品牌有自主生产闪存颗粒的技术,往往也会将好的颗粒用在自家的产品上。正因如此,这些厂家的固态硬盘往往品质比较好,使用稳定,往往价格也是最贵的。
使用原厂闪存颗粒(推荐指数:★★★☆☆)
部分使用原厂芯片厂商 - 金士顿
- 光宝
- 浦科特
这些品牌虽然没有自主生产闪存颗粒的技术,但是使用的都是原厂的闪存颗粒,然后再自己进行封装。价格便宜一些,但是稳定性不如具有自主生产闪存颗粒的厂商。
其它(推荐指数:★☆☆☆☆)
各种品牌定制,一般使用白片(原厂检测不合格的,但是能用)。或者是一些价格低的可拍的品牌,一般使用黑片。
对于这类产品,一般价格比较便宜,但是稳定性差,不推荐购买。
六、IOPS读写性能
IOPS(Input/Output Operations Per Second),是一个用于存储设备性能测试的测量方式,可以看作是每秒的读写速度。
IOPS的测试方式可以分为以下几种:
IOPS概念 主要分为随机读写测试以及顺序读写测试,如下图所示:
顺序读写 & 随机读写 比如某款500G固态的读写速度如下:
某品牌固态性能指标 其中顺序读写达到了2600MB/s,但是随机读取却没给出指标,只标注了410K IOPS(即每秒读写次数)。
再看一下三星的两款1T SSD的读写性能:
顺序读写 读写速度说明 需要注意,大多数时候的读写性能都是顺序读写的性能测试。
再来看一个因特尔的660P
intel 660p参数 参数中明确表明了随机读写/顺序读写性能。
需要注意的是,商品介绍中给出的速度一般为顺序读写的速度,某些商品会给出随机读写的IOPS指标。
SSD推荐
以下推荐按250GB、500GB、1TB、2TB排列
256GB
三星(SAMSUNG)250GB SSD固态硬盘 M.2接口 980 PRO (MZ-V8P250BW)
三星(SAMSUNG)250GB SSD固态硬盘 M.2接口 980 PRO (MZ-V8P250BW) 顺序读取:6400MB/S
顺序写入:2700MB/S
NVMe协议PCIe 4.0 x4三星(SAMSUNG)250GB SSD固态硬盘 M.2接口 970 EVO Plus(MZ-V7S250B)
三星(SAMSUNG)250GB SSD固态硬盘 M.2接口 970 EVO Plus(MZ-V7S250B) 顺序读取:3500MB/S
顺序写入:2300MB/S
NVMe协议闪迪(SanDisk)250GB SSD固态硬盘 M.2接口
闪迪(SanDisk)250GB SSD固态硬盘 M.2接口 顺序读取:2400MB/S
顺序写入:950MB/S
NVMe协议西部数据(Western Digital)250GB SSD固态硬盘 M.2接口(NVMe协议)WD_BLACK SN750
西部数据(Western Digital)250GB SSD固态硬盘 M.2接口(NVMe协议)WD_BLACK SN750 顺序读取:3100MB/S
顺序写入:1600MB/S
NVMe协议500GB
三星(SAMSUNG)500GB SSD固态硬盘 M.2接口 980 PRO (MZ-V8P500BW)
三星(SAMSUNG)500GB SSD固态硬盘 M.2接口 980 PRO (MZ-V8P500BW) 顺序写入:6900 MB/s
顺序读取:5000 MB/s
NVMe协议PCIe 4.0 x4三星(SAMSUNG)500GB SSD固态硬盘 M.2接口 970 EVO Plus(MZ-V7S500B)
三星(SAMSUNG)500GB SSD固态硬盘 M.2接口 970 EVO Plus(MZ-V7S500B) 顺序写入:3500 MB/s
顺序读取:3200 MB/s
NVMe协议闪迪(SanDisk)500GB SSD固态硬盘 M.2接口
闪迪(SanDisk)500GB SSD固态硬盘 M.2接口 顺序写入:3500 MB/s
顺序读取:3200 MB/s
NVMe协议1TB
三星(SAMSUNG)1TB SSD固态硬盘 M.2接口 980 PRO (MZ-V8P1T0BW)
三星(SAMSUNG)1TB SSD固态硬盘 M.2接口 980 PRO (MZ-V8P1T0BW) 顺序读取:7000 MB/s
顺序写入:5000 MB/s
NVMe协议PCIe 4.0 x4三星(SAMSUNG)1TB SSD固态硬盘 M.2接口(NVMe协议) 970 EVO Plus(MZ-V7S1T0B)
三星(SAMSUNG)1TB SSD固态硬盘 M.2接口(NVMe协议) 970 EVO Plus(MZ-V7S1T0B) 顺序读取:3500 MB/s
顺序写入:3300 MB/s
NVMe协议西部数据(Western Digital)1TB SSD固态硬盘 M.2接口(NVMe协议) WD_BLACK SN750
西部数据(Western Digital)1TB SSD固态硬盘 M.2接口(NVMe协议) WD_BLACK SN750 顺序读取:3400 MB/s
顺序写入:3000 MB/s
NVMe协议闪迪(SanDisk)1TB SSD固态硬盘 M.2接口
闪迪(SanDisk)1TB SSD固态硬盘 M.2接口 顺序读取:2400 MB/s
顺序写入:1950 MB/s
NVMe协议西部数据(Western Digital)1TB SSD固态硬盘 M.2接口(NVMe协议)WD Blue SN550
西部数据(Western Digital)1TB SSD固态硬盘 M.2接口(NVMe协议)WD Blue SN550 顺序读取:2400 MB/s
顺序写入:1950 MB/s
NVMe协议海康威视SSD固态硬盘C2000PRO M.2 NVME 2280接口支持笔记本台式机 C2000PRO 1T
海康威视SSD固态硬盘C2000PRO 顺序读取:3000 MB/s
顺序写入:2100 MB/s
NVMe协议2TB
西部数据(Western Digital)2TB SSD固态硬盘 PCIe Gen4技术 WD_BLACK SN850 NVMe SSD
西部数据(Western Digital)2TB SSD固态硬盘 PCIe Gen4技术 WD_BLACK SN850 NVMe SSD 顺序读取:7000 MB/s
顺序写入:5100 MB/s
NVMe协议PCIe 4.0 x4三星(SAMSUNG) 2TB SSD固态硬盘 M.2接口(NVMe协议) 970 EVO Plus(MZ-V7S2T0B)
三星(SAMSUNG) 2TB SSD固态硬盘 M.2接口(NVMe协议) 970 EVO Plus(MZ-V7S2T0B) 顺序读取:3500 MB/s
顺序写入:3300 MB/s
NVMe协议西部数据(Western Digital)2TB SSD固态硬盘 M.2接口(NVMe协议)WD Blue SN550
西部数据(Western Digital)2TB SSD固态硬盘 M.2接口(NVMe协议)WD Blue SN550 顺序读取:1800 MB/s
顺序写入:2600 MB/s
NVMe协议 -
内存管理内存管理内存管理
2011-04-04 20:16:26只是作为一个例子,让我们假定您的程序正在访问地址为 629 的内存。不过,虚拟内存系统不需要将其存储在位置为 629 的 RAM 中。实际上,它甚至可以不在 RAM 中 —— 如果物理 RAM 已经满了,它甚至可能已经被... -
org.tinygroup.jcscache-JCS缓存解决方案
2015-06-09 16:44:00org.tinygroup.jcscache是org.tinygroup.cache的具体实现,采用JSC作为缓存的技术解决方案。 JCS是Jakarta的项目Turbine的子项目。它是一个复合式的缓冲工具。可以将对象缓冲到内存、硬盘。具有缓冲对象时间过期设定...org.tinygroup.jcscache是org.tinygroup.cache的具体实现,采用JSC作为缓存的技术解决方案。 JCS是Jakarta的项目Turbine的子项目。它是一个复合式的缓冲工具。可以将对象缓冲到内存、硬盘。具有缓冲对象时间过期设定。还可以通过JCS构建具有缓冲的分布式构架,以实现高性能的应用。对于一些需要频繁访问而每访问一次都非常消耗资源的对象,可以临时存放在缓冲区中,这样可以提高服务的性能。而JCS正是一个很好的缓冲工具。缓冲工具对于读操作远远多于写操作的应用性能提高非常显著。
转载于:https://blog.51cto.com/j2eetop/1665438
-
操作系统(内存管理)
2009-09-20 12:55:25只是作为一个例子,让我们假定您的程序正在访问地址为 629 的内存。不过,虚拟内存系统不需要将其存储在位置为 629 的 RAM 中。实际上,它甚至可以不在 RAM 中 —— 如果物理 RAM 已经满了,它甚至可能已经被转移到... -
微软Sysinternals Suite工具包 2018.12.18 官方版.zip
2019-07-09 18:07:08此实用工具会捕捉所有硬盘活动,或者在您的系统任务栏中象软件磁盘活动灯一样工作。DiskView 图形磁盘扇区实用工具。Disk Usage (DU) 按目录查看磁盘使用情况。EFSDump 查看加密文件的信息。Handle 此易用命令行... -
primocache 破解版
2018-12-15 10:17:27PrimoCache破解版2018是一款可以将电脑的物理内存、SSD硬盘或闪存盘虚拟成硬盘缓存的工具,它可以自动将将硬盘中读取的数据存入物理内存等速度较快的设备。如果电脑系统将再次需要该数据时它可以很快从缓存设备中... -
开源项目学习:Android-Universal-Image-Loader-Part3
2015-03-14 21:39:38多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置支持图片的...这一次是学习作为一个工具包,怎么对外提供方法;
我们可以先看看这个开源库存在哪些特征:
- 多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
- 支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
- 支持图片的内存缓存,文件系统缓存或者SD卡缓存
- 支持图片下载过程的监听
- 根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
- 较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片
- 提供在较慢的网络下对图片进行加载
那怎么联系局部的功能(缓存...)和外部接口函数呢?
从最简单的开始:
public void displayImage(String uri, ImageAware imageAware) {
displayImage(uri, imageAware, null, null, null);
}displayImage的有很多(8个左右)重载函数,最后调用的都是一个重载函数:
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) { checkConfiguration(); if (imageAware == null) { throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS); } if (listener == null) { listener = defaultListener; } if (options == null) { options = configuration.defaultDisplayImageOptions; } if (TextUtils.isEmpty(uri)) { //engin是一个图片展示的一个引擎,细节不管 engine.cancelDisplayTaskFor(imageAware); listener.onLoadingStarted(uri, imageAware.getWrappedView()); if (options.shouldShowImageForEmptyUri()) { imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources)); } else { imageAware.setImageDrawable(null); } listener.onLoadingComplete(uri, imageAware.getWrappedView(), null); return; } ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize()); String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize); //void prepareDisplayTaskFor(ImageAware imageAware, String memoryCacheKey) { // cacheKeysForImageAwares.put(imageAware.getId(), memoryCacheKey); //把这个memoryCacheKey和imageAware的ID信息绑在一起,放到ImageLoaderEngine一个地方缓存起来-- /*调用的是: * void prepareDisplayTaskFor(ImageAware imageAware, String memoryCacheKey) { cacheKeysForImageAwares.put(imageAware.getId(), memoryCacheKey); } * 存放的数据结构是: final Map<Integer, String> cacheKeysForImageAwares = Collections .synchronizedMap(new HashMap<Integer, String>()); * */ engine.prepareDisplayTaskFor(imageAware, memoryCacheKey); listener.onLoadingStarted(uri, imageAware.getWrappedView()); //从缓存中去找对应的memoryCacheKey的数据 Bitmap bmp = configuration.memoryCache.get(memoryCacheKey); //如果内存缓存中找到了 if (bmp != null && !bmp.isRecycled()) { L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey); if (options.shouldPostProcess()) { ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, engine.getLockForUri(uri)); ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo, defineHandler(options)); if (options.isSyncLoading()) { displayTask.run(); } else { engine.submit(displayTask); } } else { options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE); listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp); } } //如果内存缓存中没有找到,就设置一些状态图片(比如正在加载的图片) else { if (options.shouldShowImageOnLoading()) { imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources)); } else if (options.isResetViewBeforeLoading()) { imageAware.setImageDrawable(null); } //这里注意了,通常我们的思路就是:既然内存缓存中没有,那么先去本地缓存上找,如果还没有就去网络上找;这就需要传URL参数进去, //从而得到我们要的Bitmap数据,再用imageAware的boolean setImageBitmap(Bitmap bitmap)就行;思路肯定是这样的,只是代码的结构安排问题; ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, engine.getLockForUri(uri)); //初始化一个任务:包括加载图片(本地缓存/网络上)和显示图片,所以这部这需要提供一些信息,封装在ImageLoadingInfo里面 //LoadAndDisplayImageTask是继承Runnable接口的,但是这个displayTask.run()还是在当前线程中进行的,没有额外开启线程;-<span style="white-space:pre"> </span>//可以有一个判断是否同步的方法isSyncLoading() LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, defineHandler(options)); if (options.isSyncLoading()) { displayTask.run(); } else { //如果是异步那么就调用ImageLoaderEngine的submit去执行 engine.submit(displayTask); } } }
首先ImageAware 是一个接口,用来提供要处理或者显示的图片的属性/行为
用的时候我们是传一个ImageView初始化对象进去,那为什么可以这样做呢?
如果是一个接口传进去,那么必须实例化,那ImageView肯定是实现了ImageAware 的一个类,那肯定也完成了一个动作:实例化ImageAware,
ImageAware aware=new ImageView();
这个地方我还没弄清楚,ImageView是andorid源码里面的东西,不可能去实现这个别人写的接口啊!--待高手指点
/** * * Represents image aware view which provides all needed properties and behavior for image processing and displaying * through {@link com.nostra13.universalimageloader.core.ImageLoader ImageLoader}. * It can wrap any Android {@link android.view.View View} which can be accessed by {@link #getWrappedView()}. Wrapped * view is returned in {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener ImageLoadingListener}'s * callbacks. * * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) * @see ViewAware * @see ImageViewAware * @see NonViewAware * @since 1.9.0 */ public interface ImageAware { /** * Returns width of image aware view. This value is used to define scale size for original image. * Can return 0 if width is undefined.<br /> * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread. */ int getWidth(); /** * Returns height of image aware view. This value is used to define scale size for original image. * Can return 0 if height is undefined.<br /> * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread. */ int getHeight(); /** * Returns {@linkplain com.nostra13.universalimageloader.core.assist.ViewScaleType scale type} which is used for * scaling image for this image aware view. Must <b>NOT</b> return <b>null</b>. */ ViewScaleType getScaleType(); /** * Returns wrapped Android {@link android.view.View View}. Can return <b>null</b> if no view is wrapped or view was * collected by GC.<br /> * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread. */ View getWrappedView(); /** * Returns a flag whether image aware view is collected by GC or whatsoever. If so then ImageLoader stop processing * of task for this image aware view and fires * {@link com.nostra13.universalimageloader.core.listener.ImageLoadingListener#onLoadingCancelled(String, * android.view.View) ImageLoadingListener#onLoadingCancelled(String, View)} callback.<br /> * Mey be called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread. * * @return <b>true</b> - if view is collected by GC and ImageLoader should stop processing this image aware view; * <b>false</b> - otherwise */ boolean isCollected(); /** * Returns ID of image aware view. Point of ID is similar to Object's hashCode. This ID should be unique for every * image view instance and should be the same for same instances. This ID identifies processing task in ImageLoader * so ImageLoader won't process two image aware views with the same ID in one time. When ImageLoader get new task * it cancels old task with this ID (if any) and starts new task. * <p/> * It's reasonable to return hash code of wrapped view (if any) to prevent displaying non-actual images in view * because of view re-using. */ int getId(); /** * Sets image drawable into this image aware view.<br /> * Displays drawable in this image aware view * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageForEmptyUri( *android.graphics.drawable.Drawable) for empty Uri}, * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageOnLoading( *android.graphics.drawable.Drawable) on loading} or * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions.Builder#showImageOnFail( *android.graphics.drawable.Drawable) on loading fail}. These drawables can be specified in * {@linkplain com.nostra13.universalimageloader.core.DisplayImageOptions display options}.<br /> * Also can be called in {@link com.nostra13.universalimageloader.core.display.BitmapDisplayer BitmapDisplayer}.< br /> * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread. * * @return <b>true</b> if drawable was set successfully; <b>false</b> - otherwise */ boolean setImageDrawable(Drawable drawable); /** * Sets image bitmap into this image aware view.<br /> * Displays loaded and decoded image {@link android.graphics.Bitmap} in this image view aware. * Actually it's used only in * {@link com.nostra13.universalimageloader.core.display.BitmapDisplayer BitmapDisplayer}.< br /> * Is called on UI thread if ImageLoader was called on UI thread. Otherwise - on background thread. * * @return <b>true</b> if bitmap was set successfully; <b>false</b> - otherwise */ boolean setImageBitmap(Bitmap bitmap); }
图片URL传进来了,要显示的地方也有了,其他的都是一些附属的配置内的东西了:缓存配置,以什么方式显示得到的图片(带特殊效果不)..还有加入2个监听器接口剩下要解决的问题就是:
1.怎么用URK从网络得到图片,里面有什么特出的处理,考虑并发了么等...?
后头看displayImage那个函数的后半部分
//初始化一个任务:包括加载图片(本地缓存/网络上)和显示图片,所以这部这需要提供一些信息,封装在ImageLoadingInfo里面 //LoadAndDisplayImageTask是继承Runnable接口的,但是这个displayTask.run()还是在主线程中进行的;--有一个是否同步的判断isSyncLoading() LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo, defineHandler(options)); if (options.isSyncLoading()) { displayTask.run(); } else { //如果是异步那么就调用ImageLoaderEngine的submit去执行 engine.submit(displayTask); }
(1)同步方法
沿着内存-》本地-》网络的思路去做,只是注意一个地方:同步方法没有开启额外的线程;
public void run() { if (waitIfPaused()) return; if (delayIfNeed()) return; ReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock; L.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey); if (loadFromUriLock.isLocked()) { L.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey); } loadFromUriLock.lock(); Bitmap bmp; try { checkTaskNotActual(); //去缓存中找数据 bmp = configuration.memoryCache.get(memoryCacheKey); if (bmp == null || bmp.isRecycled()) { 去本地缓存/网络中找数据 bmp = tryLoadBitmap(); if (bmp == null) //跳出run函数是吧?~~~~~~~~~~~~ //有些不对啊,如果是跳出去,那么就不从网络上获得数据了么? return; // listener callback already was fired checkTaskNotActual(); checkTaskInterrupted(); if (options.shouldPreProcess()) { L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey); bmp = options.getPreProcessor().process(bmp); if (bmp == null) { L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey); } } if (bmp != null && options.isCacheInMemory()) { L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey); configuration.memoryCache.put(memoryCacheKey, bmp); } } else { loadedFrom = LoadedFrom.MEMORY_CACHE; L.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey); } if (bmp != null && options.shouldPostProcess()) { L.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey); bmp = options.getPostProcessor().process(bmp); if (bmp == null) { L.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey); } } checkTaskNotActual(); checkTaskInterrupted(); } catch (TaskCancelledException e) { fireCancelEvent(); return; } finally { loadFromUriLock.unlock(); } //**********在执行这个之前就需要把图片数据得到********** DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom); runTask(displayBitmapTask, syncLoading, handler, engine); }
private Bitmap tryLoadBitmap() throws TaskCancelledException { Bitmap bitmap = null; try { File imageFile = configuration.diskCache.get(uri); if (imageFile != null && imageFile.exists() && imageFile.length() > 0) { L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey); loadedFrom = LoadedFrom.DISC_CACHE; checkTaskNotActual(); bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath())); } if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) { L.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey); loadedFrom = LoadedFrom.NETWORK; String imageUriForDecoding = uri;
//如果用户配置了本地缓存,那么从网络上得到的数据保存在本地,再去从本地取得--
//最终用到的是HttpURLConnection conn = createConnection(imageUri, extra); if (options.isCacheOnDisk() && tryCacheImageOnDisk()) { imageFile = configuration.diskCache.get(uri); if (imageFile != null) { imageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath()); } } checkTaskNotActual(); bitmap = decodeImage(imageUriForDecoding); if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) { fireFailEvent(FailType.DECODING_ERROR, null); } } } catch (IllegalStateException e) { fireFailEvent(FailType.NETWORK_DENIED, null); } catch (TaskCancelledException e) { throw e; } catch (IOException e) { L.e(e); fireFailEvent(FailType.IO_ERROR, e); } catch (OutOfMemoryError e) { L.e(e); fireFailEvent(FailType.OUT_OF_MEMORY, e); } catch (Throwable e) { L.e(e); fireFailEvent(FailType.UNKNOWN, e); } return bitmap; }
(2)异步任务异步任务是用线程池完成的,线程池的
异步任务传入的参数还是LoadAndDisplayTask这个类的实例,
void submit(final LoadAndDisplayImageTask task) { taskDistributor.execute(new Runnable() { @Override public void run() { File image = configuration.diskCache.get(task.getLoadingUri()); boolean isImageCachedOnDisk = image != null && image.exists(); initExecutorsIfNeed();
//如果在本地已经有缓存的话,那么就用taskExecutorForCachedImages;默认情况下(用户没有配置)2个Excutor默认情况下开启的线程池大小、优先级、处理类型都是一样的 if (isImageCachedOnDisk) { taskExecutorForCachedImages.execute(task); } else { taskExecutor.execute(task); } } }); }
taskDistributor的实例化是这么完成的:public static Executor createTaskDistributor() { return Executors.newCachedThreadPool(createThreadFactory(Thread.NORM_PRIORITY, "uil-pool-d-")); }
taskExecutorForCachedImages(task);和 taskExecutor.execute(task);--他们的Executor实例化都是ImageLoaderConfiguration配置好的传进来的
/*
if (taskExecutorForCachedImages == null) {
taskExecutorForCachedImages = DefaultConfigurationFactory
.createExecutor(threadPoolSize, threadPriority, tasksProcessingType);
}*/
分析道最后,发现有一个译文
http://www.cnblogs.com/kissazi2/p/3886563.html
这里的写的很清楚,一篇篇看下去比我写的清楚多了~原因是自己对各个知识点还不是非常熟悉,能看懂但是不能熟练掌握,领悟到一点:写文章也是一门细活,还是考验熟练程度的一个东西~
-
eboostr 3.0 正式破解版
2011-07-16 02:46:08eBoostr 4.0[U盘变内存、变硬盘缓存]注册码 Vista有一项新增的ReadyBoost功能,它可以把闪存中的空间虚拟成缓存,依靠其高速随机访问能力为系统进行加速。 MDO公司发布了eBoostr ,通过它可以使用附加驱动器(包括... -
NoSql之Redis学习
2018-06-11 22:25:46NoSql由于直接存储在内存中,读写速度远远快于读取存储在硬盘中数据库,但是它并不具备取代现有数据库的能力,因为它是结构松散、不完整,功能有限,但是作为缓存工具,它具备了高性能、高响应等功能,成为了一种... -
电脑蓝屏对照码
2019-05-05 14:16:40◆错误分析:系统内存存储器奇偶校验产生错误, 通常是因为有缺陷的内存(包括物理内存、二级缓存或者显卡显存)时设备驱动程序访问不存在的内存地址等原因引起的. 另外, 硬盘被病毒或者其他问题所损伤, 以出现这个停机... -
服务器基础知识篇,工作组级服务器
2008-12-09 13:28:44集成了RAID控制器并配备了128MB缓存,可以为用户提供0、1、5、10四个级别的RAID,最大可以支持10个热插拔硬盘并提供730GB的磁盘存储空间。 由于是面向企业级应用,所在在可维护性以及冗余性能上有其独到的地方,... -
WIN XP蓝屏代码大全
2013-08-08 12:29:21◆错误分析:系统内存存储器奇偶校验产生错误, 通常是因为有缺陷的内存(包括物理内存、二级缓存或者显卡显存)时设备驱动程序访问不存在的内存地址等原因引起的. 另外, 硬盘被病毒或者其他问题所损伤, 以出现这个停机... -
电脑常见问题与故障1000例(高清PDF中文版)
2011-05-30 07:13:36本书既可以作为一本电脑故障排除方面的通俗教材,也可以当作速查手册使用。通过本书的讲解,相信对计算机用户会有很大的帮助。 目录: 第1章 硬件故障 1.1 CPU故障 1.CPU温度过高造成死机 2.计算机自动关机或重启 ... -
Microsoft SQL Server 2005技术内幕:存储引擎(中文).pdf
2012-06-23 13:15:03管理其他高速缓存中的内存 调节内存大小 调节缓存池大小 2.3 小结 第3章 SQL Server 2005的配置 3.1 使用SQL Server 配置管理器 配置网络协议 默认的网络配置 管理服务 3.2 系统配置 ... -
Windows Sysinternals Suite v2019.06.29.zip
2019-07-14 18:41:59此实用工具会捕捉所有硬盘活动,或者在您的系统任务栏中象软件磁盘活动灯一样工作。 DiskView 图形磁盘扇区实用工具。 Disk Usage (DU) 按目录查看磁盘使用情况。 EFSDump 查看加密文件的信息。 Handle 此... -
注册表批量修改权限命令
2016-11-09 11:40:27此实用工具会捕捉所有硬盘活动,或者在您的系统任务栏中象软件磁盘活动灯一样工作。 DiskView 图形磁盘扇区实用工具。 Disk Usage (DU) 按目录查看磁盘使用情况。 EFSDump 查看加密文件的信息。 Handle 此易用命令行... -
计算机应用技术(实用手册)
2011-07-29 16:32:16内存为512兆 32兆的二级缓存 IDE Channel 0 master : None IDE Channel 0 Slave : None IDE Channel 1 master : HL-DT-STDVD-ROM GDR8164B 0L06 IDE Channel 1 Slave : None IDE Channel 2 master : WDC WD800BD-00... -
LINUX系统分析与高级编程技术
2010-09-17 22:56:0919.6.7 使用共享内存的实例:shmtool 第二十章 高级线程编程 20.1 线程的概念和思想 20.2 一个简单的例子 20.3 线程同步 20.4 使用信号量协调程序 20.5 信号量的实现 20.5.1 Semaphore.h 20.5.2Semaphore.c 第二... -
LINUX系统分析与高级编程技术.rar
2009-05-20 18:26:304.5 使用文件作为交换区 31 4.6 系统和文件的备份 32 4.7 设置系统 33 4.7.1 设置系统名 33 4.7.2 使用维护磁盘 33 4.7.3 重新设置root 帐号口令 33 4.7.4 设置登录信息 33 第二篇 Linux高级语言及管理编程 第5章 ... -
Nginx安装包
2017-09-01 14:17:19与一般数据库不同,redis是使用内存作为主存,而使用硬盘来实现数据持久化,而且redis是周期性的将数据写到硬盘上。这就意味着一旦我们服务器出现断电、重启之类的情况,我们很可能会出现数据丢失的情况,所以不建议... -
尹成Python27天入门到项目实战
2020-12-05 17:04:22python入门与学习方法精确思维与用到才能记忆深刻课程简介课前介绍计算机简介与硬盘概念内存作用计算机小结编程语言简介操作系统简介python版本简介切换python版本修改环境变量交互式编程两种风格python3代码保存... -
电脑高手必备 Windows系统35招实用技巧
2009-06-11 14:42:10内存作为磁盘读写的高速缓存可以有效提高系统运行效率。Smartdrv.exe这 个文件在Windows各个版本的安装光盘中或是硬盘上的Windows/command/里都 有,只有几十KB,把这个文件复制到软盘下,启动系统后直接运行这个... -
当你系统崩溃时教你如何重装系统
2010-10-17 23:13:57候运行一下,有时候忘了,可我没有感觉到有多大的差别,也可能我的电脑内存比较大?说不清) 如果你是在原有系统不变、系统硬盘上有xx作系统的情况下重新安装XP,在安装的过程中会出现《升 级/全新安装》对话框,... -
2004-2010软考程序员真题
2012-09-27 12:33:00A)硬盘中的一块区域 B)软盘中的一块区域 C)高速缓存中的一块区域 D)内存中的一块区域 26、下面是关于Windows 98文件名的叙述,错误的是 A)文件名中允许使用汉字 B)文件名中允许使用多个圆点分隔符 C)文件名...
-
美团外卖Android平台化架构演进实践
-
蓝桥练习题(JAVA)——打印十字图
-
基于采用级联调制器的光电振荡器的自振荡光学频率梳状发生器
-
CS3100-UNO-源码
-
Session的使用
-
vue的生命周期
-
bert_sentiment_analysis_finetuning-源码
-
量子差分密码分析
-
龙芯生态应用开发基础:C语言精要
-
FTP 文件传输服务
-
VS2019 getline()
-
JavaWeb之MVC三层架构
-
scala:分别使用懒汉式和饿汉式实现单例模式
-
Glasterfs 分布式网络文件系统
-
UL 859:2017 Household Electric Personal Grooming Appliances(个人护理)-完整英文版(192页)
-
ApacheFlink漫谈系列-概述
-
docker基本使用教程, 以及docker部署flask框架示例
-
python数据分析之Pandas数据结构和操作
-
ASHRAE_Extended_Environmental_Envelope_Final_Aug_1_2008.pdf
-
Flutter布局详解