本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处!

从Android爆发以后,自定义的控件如EditTextWithDelete、ActionBar、PullToRresh逐步进入开发者的视野,想起11年的时候,基本项目中使用的UI还全都是Android提供的基础控件,少一点的动画+布局,下载和网络请求都是用HttpClient,图片加载当然也是下载后再使用,当时的程序资源可没有现在这么丰富,看看Github上开源的项目,现在的程序员应该感到幸福。

项目开发从程序上来讲,万古不变两大事情,一是网络通信框架,二是图片加载框架,有关网络框架上一篇已经介绍了async-http和okhttp,而其他如volly同时拥有网络请求和图片加载两个框架,很多人图省事就一次性使用了,当然facebook自己的开源框架也是写的非常不错,接下来再一一介绍;先贴一张11年我们自己写的imageloader

public class ImageDownloader {

	private static ImageDownloader instance = null;
private static File cacheDir;
public static Map<String, SoftReference<Bitmap>> bitMapCache = new HashMap<String, SoftReference<Bitmap>>(); public static ImageDownloader getInstance() {
if (instance == null) {
instance = new ImageDownloader();
}
return instance;
} private ImageDownloader() {
// Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED))
cacheDir = new File(
android.os.Environment.getExternalStorageDirectory(),
"WholeMag");
else
cacheDir = WholeMagApplication.getInstance().getCacheDir();
if (!cacheDir.exists())
cacheDir.mkdirs();
} public void download(String actName, String url, ImageView imageView) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView, actName);
task.execute(url);
// return task.doInBackground(url);
} class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
// private String url;
// private boolean flag;
private final WeakReference<ImageView> imageViewReference; // 使用WeakReference解决内存问题
private String actName; public BitmapDownloaderTask(ImageView imageView, String actName) {
imageViewReference = new WeakReference<ImageView>(imageView);
this.actName = actName;
} @Override
protected Bitmap doInBackground(String... params) { // 实际的下载线程,内部其实是concurrent线程,所以不会阻塞
Bitmap rebmp = getLocalBitmap(params[0], actName);
if (rebmp == null)
rebmp = downloadBitmap(params[0], actName);
if (rebmp == null) {
doInBackground(params[0]);
}
return rebmp;
} @Override
protected void onPostExecute(Bitmap bitmap) { // 下载完后执行的
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setDrawingCacheEnabled(true);
Bitmap temp = imageView.getDrawingCache();
imageView.setDrawingCacheEnabled(false);
if (temp != null) {
temp.recycle();
}
double widthX = (float) WholeMagDatas.getDeviceWidth()
/ bitmap.getWidth(); // 图片宽度拉伸比例
int bitmapHight = bitmap.getHeight();// 图片高度
imageView.setImageBitmap(bitmap); // 下载完设置imageview为刚才下载的bitmap对象
if(actName.equals(AppData.NEWS_DETAIL_ACT)){
FrameLayout.LayoutParams ll = new FrameLayout.LayoutParams(
android.view.ViewGroup.LayoutParams.FILL_PARENT,
(int) (bitmapHight * widthX), Gravity.CENTER);
imageView.setLayoutParams(ll);
}
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);// 创建一个AlphaAnimation对象
alphaAnimation.setDuration(500);// 设置动画执行的时间(单位:毫秒)
imageView.startAnimation(alphaAnimation);
}
}
}
} static Bitmap getLocalBitmap(String url, String actName) {
if (bitMapCache.containsKey(url)) {
return bitMapCache.get(url).get();
}
// String tmp = url;
// String first = url.substring(url.lastIndexOf("/") + 1);
// tmp = tmp.substring(0, tmp.lastIndexOf("/"));
// String second = tmp.substring(tmp.lastIndexOf("/") + 1);
// tmp = tmp.substring(0, tmp.lastIndexOf("/"));
// String third = tmp.substring(tmp.lastIndexOf("/") + 1);
// String filename = third + second + first;
// File f = new File(cacheDir, filename);
File f = Tools.getFile(actName, url);
InputStream inputStream = null;
try {
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inPreferredConfig = Bitmap.Config.RGB_565;
o.inDither = false;
o.inPurgeable = true;
// o.inTempStorage = new byte[12 * 1024];
inputStream = new FileInputStream(f);
// Bitmap bitmap = BitmapFactory.decodeFile(f.getAbsolutePath());
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, o);
bitMapCache.put(url, new SoftReference<Bitmap>(bitmap));
return bitmap;
} catch (Exception e) {
} finally {
if (null != inputStream) {
try {
inputStream.close();
} catch (Exception ex) {
}
}
}
return null;
} static Bitmap downloadBitmap(String url, String actName) {
final AndroidHttpClient client = AndroidHttpClient.newInstance("linux");
final HttpGet getRequest = new HttpGet(url); try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
// Log.e("cwjDebug", "Error " + statusCode
// + " while retrieving bitmap from " + url);
return null;
} final HttpEntity entity = response.getEntity();
if (entity != null) {
// String tmp = url;
// String first = url.substring(url.lastIndexOf("/") + 1);
// tmp = tmp.substring(0, tmp.lastIndexOf("/"));
// String second = tmp.substring(tmp.lastIndexOf("/") + 1);
// tmp = tmp.substring(0, tmp.lastIndexOf("/"));
// String third = tmp.substring(tmp.lastIndexOf("/") + 1);
// String filename = third + second + first;
// File f = new File(cacheDir, filename);
File f = Tools.getFile(actName, url);
OutputStream os = new FileOutputStream(f);
InputStream inputStream = null;
try {
inputStream = entity.getContent();
BitmapFactory.Options o = new BitmapFactory.Options();
o.inPreferredConfig = Bitmap.Config.RGB_565;
o.inDither = false;
o.inPurgeable = true;
final Bitmap bitmap = BitmapFactory.decodeStream(
inputStream, null, o);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
bitMapCache.put(url, new SoftReference<Bitmap>(bitmap));
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (null != os) {
os.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
getRequest.abort();
} finally {
if (client != null) {
client.close();
}
}
return null;
}
}

当年为了防止图片爆掉出现OOM,使用了软引用,觉得还不错;图片加载的基本原理就是,把url+imageview抛过来,然后开启异步线程加载,根据获取的byte流decode成bitmap,最后在UI线程将图片加载到imageview上;也没有说做本地缓存,仅做了应用缓存;没有对图片进行压缩或者设置格式,使占用内存更小,展示也更合理;LruCache基本原理跟上面使用软引用的过程差不多,只不过多限制了图片占用内存的大小,计算图片使用的频率,对应用层、SD卡层均做了封装。

上面介绍完,相信你也对图片加载有个大概的轮廓,我们拿开源的imageloader为例,来讲讲图片加载框架的一些细节

public final class ImageLoaderConfiguration {

    final Resources resources;//主要给图片设计宽高时,获得屏幕宽高使用
    final int maxImageWidthForMemoryCache;//内存中最大的图片宽度
final int maxImageHeightForMemoryCache;//内存中最大的图片高度
    final int maxImageWidthForDiskCache;//SD卡中最大的图片宽度
final int maxImageHeightForDiskCache;//SD卡中最大的图片高度
final BitmapProcessor processorForDiskCache;//从SD卡获得Bitmap的加载器 final Executor taskExecutor;//加载图片时的执行器
final Executor taskExecutorForCachedImages;//加载缓存时的执行器
final boolean customExecutor;//是否使用默认执行器
final boolean customExecutorForCachedImages;//是否使用默认缓存执行器 final int threadPoolSize;//线程数,可以用来控制展示当前界面的item图片
final int threadPriority;//线程的执行优先级
final QueueProcessingType tasksProcessingType;//是LILO还是LIFO,默认是前者,但一般喜欢后者 final MemoryCache memoryCache;//内存缓存对象,如不写可用默认
final DiskCache diskCache;//SD卡缓存对象,如不写可用默认
final ImageDownloader downloader;//图片加载器,根据网络(http/s)、file、content、drawable、asset来加载
final ImageDecoder decoder;//图片解析器,根据获取的图片参数拿到Bitmap
final DisplayImageOptions defaultDisplayImageOptions;//设置图片加载状态和结果,见下面源码 final ImageDownloader networkDeniedDownloader;//不用网络下载图片的下载器,可理解为加载SD卡图片的加载器
final ImageDownloader slowNetworkDownloader;//仅网络下载图片的下载器,支持断点续传

拿这些变量来讲,基本就可以说明事情 

public final class DisplayImageOptions {

    private final int imageResOnLoading;//图片是否加载中
private final int imageResForEmptyUri;//图片是否来自于空url
private final int imageResOnFail;//图片是否加载失败
private final Drawable imageOnLoading;//加载中的图片
private final Drawable imageForEmptyUri;//空数据的图片
private final Drawable imageOnFail;//加载失败的图片
private final boolean resetViewBeforeLoading;//加载完是否重置(意味着放弃之前的加载)
private final boolean cacheInMemory;//是否缓存在内存中
private final boolean cacheOnDisk;//是否缓存在SD卡中
private final ImageScaleType imageScaleType;//要多大的图片,统一设置
private final Options decodingOptions;//Bitmap的options对象
private final int delayBeforeLoading;//是否延迟加载,可用于非当前页面图片
private final boolean considerExifParams;//是否支持jpeg图片的rotate和flip等方法
private final Object extraForDownloader;//额外数据
private final BitmapProcessor preProcessor;//加载不在内存中的图片
private final BitmapProcessor postProcessor;//加载在图片中的图片
private final BitmapDisplayer displayer;//展示图片
private final Handler handler;//这个就不用讲了吧,跟主线程交互必不可少的工具
private final boolean isSyncLoading;//是否同步加载

补充一下,上面框架还支持给图片设置像素点占位大小;看到这么多功能,对于现在的项目基本满足要求,因此就不打算换了,再看看其他几种图片加载框架的异同

fresco,facebook出品,最大的优势在于可展示加载过程,即加载进度、加载前图片、加载中图片、加载后图片、加载失败图片等,还可以设置图片的形状;并且提供加载Gif、Webp图片的方法。

picasso,加载更快,因为默认设置图片格式占内存小

Glide是升级版本的piccaso,支持跟fragment和activity生命周期绑定

volly,基于老的imageloader又做了次封装,差别不是太大,功能弱化一些

而后面这几种框架,都是在imageloader兴起之后出现的,所以也基本支持它,在我看来也仅有fresco和glide是真正写出了跟原框架不同的东西。

Android项目框架之图片加载框架的选择的更多相关文章

  1. Android中常见的图片加载框架

    图片加载涉及到图片的缓存.图片的处理.图片的显示等.而随着市面上手机设备的硬件水平飞速发展,对图片的显示要求越来越高,稍微处理不好就会造成内存溢出等问题.很多软件厂家的通用做法就是借用第三方的框架进行 ...

  2. Android 框架练成 教你打造高效的图片加载框架(转)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41874561,本文出自:[张鸿洋的博客] 1.概述 优秀的图片加载框架不要太多, ...

  3. Android 框架练成 教你打造高效的图片加载框架

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41874561,本文出自:[张鸿洋的博客] 1.概述 优秀的图片加载框架不要太多, ...

  4. Android图片加载框架最全解析(八),带你全面了解Glide 4的用法

    本篇将是我们这个Glide系列的最后一篇文章. 其实在写这个系列第一篇文章的时候,Glide就推出4.0.0的RC版了.那个时候因为我一直研究的都是Glide 3.7.0版本,再加上RC版本还不太稳定 ...

  5. Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能

    我们的Glide系列文章终于要进入收尾篇了.从我开始写这个系列的第一篇文章时,我就知道这会是一个很长的系列,只是没有想到竟然会写这么久. 在前面的六篇文章中,我们对Glide的方方面面都进行了学习,包 ...

  6. Android图片加载框架最全解析(六),探究Glide的自定义模块功能

    不知不觉中,我们的Glide系列教程已经到了第六篇了,距离第一篇Glide的基本用法发布已经过去了半年的时间.在这半年中,我们通过用法讲解和源码分析配合学习的方式,将Glide的方方面面都研究了个遍, ...

  7. Android图片加载框架最全解析(五),Glide强大的图片变换功能

    大家好,又到了学习Glide的时间了.前段时间由于项目开发紧张,再加上后来又生病了,所以停更了一个月,不过现在终于又可以恢复正常更新了.今天是这个系列的第五篇文章,在前面四篇文章的当中,我们已经学习了 ...

  8. Android图片加载框架最全解析(三),深入探究Glide的缓存机制

    在本系列的上一篇文章中,我带着大家一起阅读了一遍Glide的源码,初步了解了这个强大的图片加载框架的基本执行流程. 不过,上一篇文章只能说是比较粗略地阅读了Glide整个执行流程方面的源码,搞明白了G ...

  9. Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

    在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API.还没有看过上一篇文章的朋友,建议先去阅读 Android图片加载框架最全解析(一),G ...

随机推荐

  1. Animator窗口视图Project视图PlayerIdleAnimation和PlayerWalkingAnimation

    Animator窗口视图Project视图PlayerIdleAnimation和PlayerWalkingAnimation 通过上一小节的操作,我们新建了2个动画:PlayerIdleAnimat ...

  2. POJ1797 Heavy Transportation(SPFA)

    题目要求1到n点的最大容量的增广路. 听说是最短路求的,然后乱搞就A了.. 大概能从Bellman-Ford的思想,dk[u]表示从源点出发经过最多k条边到达u点的最短路,上理解正确性. #inclu ...

  3. 基于Extjs的web表单设计器 第五节——数据库设计

    这里列出表单设计器系列的内容,6.7.8节的内容应该在春节后才有时间出了.因为这周末就请假回老家了,准备我的结婚大事.在此提前祝大家春节快乐! 基于Extjs的web表单设计器 基于Extjs的web ...

  4. BZOJ3577 : 玩手机

    很明显网络流. S到每个发射站连边,容量为该站限制 每个接收站到T连边,容量为该站限制 矩阵每个点拆成两个点i和i',i向i'连边,容量为该位置手机数 每个发射站向该正方形内所有点i连边,容量为无穷大 ...

  5. BZOJ2610 : [Poi2003]Monkeys

    考虑离线,将删边操作倒过来变成加边,等价于询问每个点什么时候与1连通 使用并查集维护,每次合并时如果有一边是1所在连通块,就把另一边的所有点的答案更新 #include<cstdio> # ...

  6. BZOJ3881 : [Coci2015]Divljak

    对Alice的所有串构造AC自动机,并建出Fail树 每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1 需要注意的是每次操作,相同的点只能被加一次 所以在需要操 ...

  7. TYVJ P1020 寻找质因数

    做题记录:2016-08-08 描述 给出N个数字,试求质因数最大的数字. 输入格式 第一行,一个整数N,表示数字个数.接下来N行,每行一个整数A_i,表示给出的数字. 输出格式 一个整数,表示质因数 ...

  8. 1^b+2^b+3^b+...+n^b数列

    首先,这是我自己推出来的,O(n^2),常数巨大.所以无能为力优化!所以求此数列的公式!求优化!!! 主要思想:要算b次的,那么就要先算b+1次的. 首先,我用F(i, j)表示杨辉三角第i层第j个, ...

  9. 51NOD 算法马拉松12

    OTZ做出题目的神犇..断断续续改完了在这里存一下思路吧 A题:第K大区间题意:定义一个区间的值为其众数出现的次数.现给出n个数,求将所有区间的值排序后,第K大的值为多少. 分析:二分答案mid,任务 ...

  10. oracle系列--第一篇 数据库基础

    第一章 数据库基础 1.1 数据管理概述 1.1.1 什么是数据管理 与我们人类相比,计算机的最大优势就是能够高速.精准地运行,其运行的过程就是执行程序代码和操作指令.处理数据的过程.可以说,数据处理 ...