尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44344085

接触android有半年了。关于图片异步载入。一直仅仅用别人的框架,尽管特别方便,可是始终未见识到图片异步载入的庐山真面目。

近期比較悠闲,研究一些高大上的东西。在这篇文章总结一下我对图片异步载入的一些学习心得。

图片载入最重要的无非就是内存和线程。

大家都知道关于内存溢出一般的解决方式就是LruCache,在我的这个demo里我仅仅要使用SoftReference实现了一个缓存类,SoftReference已经被遗弃了,这里仅仅为学习。

代码

com.example.qtdemo_oom.Cache<T, U>

/**
* 由SoftReference实现的内存缓存<br>
* 此类仅供学习,因为Android 2.3開始,垃圾回收器倾向于回收软引用和弱引用对象。
* @author qingtian
*/
public class Cache<T,U> { private Hashtable<T, NewSoftReference> hashTable;// 用于Chche内容的存储
private ReferenceQueue<U> q;// 垃圾Reference的队列 /**
* 继承SoftReference,使得每个实例都具有可识别的标识。 */
private class NewSoftReference extends SoftReference<U> {
public T key;
public NewSoftReference(U em, ReferenceQueue<U> q) {
super(em, q);
}
} /**
* 构建一个缓存器实例
*/
public Cache() {
hashTable = new Hashtable<T, NewSoftReference>();
q = new ReferenceQueue<U>();
} /**
* 保存一个实例
* @param t
* @param u
*/
public void put(T t, U u) {
cleanCache();// 清除垃圾引用
NewSoftReference ref = new NewSoftReference(u, q);
ref.key = t;
hashTable.put(t, ref);
} /**
* 通过uri获取实例
* @param t
* @return
*/
public U get(T t) {
U bm = null;
if (hashTable.containsKey(t)) {
NewSoftReference ref = (NewSoftReference) hashTable.get(t);
bm = (U) ref.get();
}
return bm;
} /**
* 在hashTable里里清除已经被回收了的对象的软引用对象
*/
@SuppressWarnings("unchecked")
private void cleanCache() {
NewSoftReference ref = null;
while ((ref = (NewSoftReference) q.poll()) != null) {
hashTable.remove(ref.key);
}
} /**
* 清除Cache内的所有内容
*/
public void clearCache() {
cleanCache();
hashTable.clear();
System.gc();
System.runFinalization();
}
}

com.example.qtdemo_oom.ImageLoader

/**
* 图片载入工具类
* @author qingtian
*/
public class ImageLoader { private static final String TAG = "qingtian" ; //线程池
ExecutorService threadPool ;
//自己实现的缓存类
Cache<String, Bitmap> cache;
//也能够用v4包提供的缓存
// LruCache<String, Bitmap> cache; public ImageLoader() {
threadPool = new ThreadPoolExecutor(2, 2, 0, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
cache = new Cache<String, Bitmap>();
// int maxMemory = (int) Runtime.getRuntime().maxMemory();
// cache = new LruCache<String, Bitmap>(maxMemory/8){
// // 測量Bitmap的大小
// @Override
// protected int sizeOf(String key, Bitmap value) {
// return value.getRowBytes() * value.getHeight();
// }
// };
} private int currentThreadNum = 0; class DownBitmapRunnable implements Runnable{
ImageView iv; String uri;
public DownBitmapRunnable( ImageView iv, String uri) {
this.iv = iv;
this.uri = uri;
}
@Override
public void run() { currentThreadNum++; show(); Bitmap bm = cache.get(uri);
if (bm == null) {
Log.i(TAG, "下载");
bm = BitmapUtil.getImageBitmap(uri);
}else{
Log.i(TAG, "不下载");
}
if (bm != null) {
cache.put(uri, bm);
final Bitmap fBitmap = bm;
new Handler(Looper.getMainLooper()).post(new Runnable() { @Override
public void run() {
iv.setImageBitmap(fBitmap);
} });
} currentThreadNum--;
} } public void show( ImageView iv, String uri) { threadPool.execute(new DownBitmapRunnable(iv, uri)); } public void show() {
Log.i(TAG, "currentThreadNum:" + currentThreadNum );
}
}

在这个类里。使用线程池管理线程。避免创建/取消线程时内存的浪费。第14行代码也提供了LruCache代码,我们也能够用LruCache来实现缓存。

代码第54--61行,对于view的操作已经在主线程里了。

com.example.qtdemo_oom.Adapter

public class Adapter extends BaseAdapter {
public static final String[] uris = new String[] {
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img1b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img2b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img3b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img4b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img5b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img6b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img7b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img8b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img9b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img10b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img11b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img12b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img13b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img14b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img15b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img16b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img17b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img18b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img19b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img20b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img21b.jpg",
"http://mabinbin.com:8080/AndroidAsyncHttpService/image/img22b.jpg" }; public LayoutInflater mInflater;
public ImageLoader loader; public Adapter(Context context) {
mInflater = LayoutInflater.from(context);
loader = new ImageLoader();
} @Override
public int getCount() {
return uris.length;
} @Override
public Object getItem(int arg0) {
return uris[arg0];
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item, null); holder = new ViewHolder();
holder.tv = (TextView) convertView.findViewById(R.id.tv);
holder.iv = (ImageView) convertView.findViewById(R.id.iv);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
} holder.tv.setText((String) getItem(position)); loader.show(holder.iv, uris[position]); return convertView;
} class ViewHolder {
TextView tv;
ImageView iv;
} }

代码第66行,就能够异步载入图片了。

com.example.qtdemo_oom.util.BitmapUtil

public class BitmapUtil {

	public static Bitmap getImageBitmap(String uri) {
URL imgUrl = null;
Bitmap bitmap = null;
InputStream is = null;
try {
imgUrl = new URL(uri);
HttpURLConnection conn = (HttpURLConnection) imgUrl
.openConnection();
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
is = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bitmap;
} }

通过这个简单的demo,我见到了内存缓存的真面目。也学习了LruCache的源代码(这里没体现)。

当然这是我学习异步图片载入的第一版,希望在后面的版本号里写的更成熟。

源代码下载

自己动手写android图片异步载入库的更多相关文章

  1. Android图片异步加载

    原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.html 相关:https://github.com/nostra13/A ...

  2. 一起写一个Android图片加载框架

    本文会从内部原理到具体实现来详细介绍如何开发一个简洁而实用的Android图片加载缓存框架,并在内存占用与加载图片所需时间这两个方面与主流图片加载框架之一Universal Image Loader做 ...

  3. Android 图片异步加载的体会,SoftReference已经不再适用

      在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的 ...

  4. Android图片异步加载之Android-Universal-Image-Loader

    将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...

  5. Android图片异步加载之Android-Universal-Image-Loader(转)

    今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决 ...

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

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

  7. fackbook的Fresco (FaceBook推出的Android图片加载库-Fresco)

    [Android开发经验]FaceBook推出的Android图片加载库-Fresco   欢迎关注ndroid-tech-frontier开源项目,定期翻译国外Android优质的技术.开源库.软件 ...

  8. Android 图片加载库Glide 实战(二),占位符,缓存,转换自签名高级实战

    http://blog.csdn.net/sk719887916/article/details/40073747 请尊重原创 : skay <Android 图片加载库Glide 实战(一), ...

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

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

随机推荐

  1. Audio Unit 介绍

    关于 Audio Unit iOS 提供了音频处理插件,支持混音,声音均衡,格式转化,以及用于录音,回放,离线渲染,实时对话的输入输出.可以动态载入和使用这些强大而灵活的插件,在 iOS 应用中这些插 ...

  2. 将PHP程序中返回的JSON格式数据用gzip压缩输出

    //phpinfo(); 搜索下 zlib 是否开启 //此示例开启压缩 Content-Length:124 Size: 404B //未开启gzip压缩 Content-Length:675 Si ...

  3. POJ1018 Communication System

      Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 26738   Accepted: 9546 Description We ...

  4. noi2017 T1 整数 ——线段树

    loj.ac上有  题目传送门 不过我还是把题目搬过来吧 整数(integer)[题目背景]在人类智慧的山巅,有着一台字长为 1048576 位的超级计算机,著名理论计算机科 学家 P 博士正用它进行 ...

  5. Html5学习进阶三 Input 类型

    HTML5 新的 Input 类型 HTML5 拥有多个新的表单输入类型.这些新特性提供了更好的输入控制和验证. 本章全面介绍这些新的输入类型: email url number range Date ...

  6. C# 操作Excel,使用EPPlus

    EPPlus下载地址:http://www.codeplex.com/EPPlus 引用命名空间: using OfficeOpenXml; using OfficeOpenXml.Table; us ...

  7. Linux单机安转Spark

    安装Spark需要先安装jdk及安装Scala. 1. 创建目录 > mkdir  /opt/spark > cd  /opt/spark 2. 解压缩.创建软连接 > tar  z ...

  8. Python之jieba分词

    jieba,很有意思的一个模块,专门用来分词. import jieba # sentence:分割的中文字符串 # cut_all:是否采用全模式,默认为False表示精确模式 # HMM:表示是否 ...

  9. mysq 中 information_schema 库

    information_schema这个库,这个在mysql安装时就有了,提供了访问数据库元数据的方式.那什么是元数据库呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等.有些时 ...

  10. Selenium2+python自动化10-登录案例【转载】

    前言 前面几篇都是讲一些基础的定位方法,没具体的案例,小伙伴看起来比较枯燥,有不少小伙伴给小编提建议以后多出一些具体的案例.本篇就是拿部落论坛作为测试项目,写一个简单的登录测试脚本. 在写登录脚本的时 ...