在Android的应用中实现网络图片异步加载的方法
程序员文章站
2024-03-05 12:16:06
前言
其实很幸运,入职一周之后就能跟着两个师兄做android开发,师兄都是大神,身为小白的我只能多多学习,多多努力。最近一段时间都忙的没机会总结,今天刚完成了andro...
前言
其实很幸运,入职一周之后就能跟着两个师兄做android开发,师兄都是大神,身为小白的我只能多多学习,多多努力。最近一段时间都忙的没机会总结,今天刚完成了android客户端图片异步加载的类,这里记录一下(ps:其实我这里都是参考网上开源实现)
原理
在listview或者gridview中加载图片的原理基本都是一样的:
先从内存缓存中获取,取到则返回,取不到进行下一步
从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行进行下一步
从网络上下载图片,并更新内存缓存和文件缓存
流程图如下:
同时,要注意线程的数量。一般在listview中加载图片,大家都是开启新的线程去加载,但是当快速滑动时,很容易造成oom,因此需要控制线程数量。我们可以通过线程池控制线程的数量,具体线程池的大小还需要根据处理器的情况和业务情况自行判断
建立线程池的方法如下:
executorservice executorservice = executors.newfixedthreadpool(5); // 5是可变的
文件缓存类
import java.io.file; import android.content.context; public class filecache { private static final string dir_name = "your_dir"; private file cachedir; public filecache(context context) { // find the directory to save cached images if (android.os.environment.getexternalstoragestate().equals( android.os.environment.media_mounted)) { cachedir = new file( android.os.environment.getexternalstoragedirectory(), dir_name); } else { cachedir = context.getcachedir(); } if (!cachedir.exists()) { cachedir.mkdirs(); } } public file getfile(string url) { // identify images by url's hash code string filename = string.valueof(url.hashcode()); file f = new file(cachedir, filename); return f; } public void clear() { file[] files = cachedir.listfiles(); if (files == null) { return; } else { for (file f : files) { f.delete(); } } } }
内存缓存类
这里使用了软引用,map<string, softreference<bitmap>> cache,可以google一下软引用的机制,简单的说:实现了map,同时当内存紧张时可以被回收,不会造成内存泄露
import java.lang.ref.softreference; import java.util.collections; import java.util.linkedhashmap; import java.util.map; import android.graphics.bitmap; public class memorycache { private map<string, softreference<bitmap>> cache = collections .synchronizedmap(new linkedhashmap<string, softreference<bitmap>>( 10, 1.5f, true)); public bitmap get(string id) { if (!cache.containskey(id)) { return null; } softreference<bitmap> ref = cache.get(id); return ref.get(); } public void put(string id, bitmap bitmap) { cache.put(id, new softreference<bitmap>(bitmap)); } public void clear() { cache.clear(); } }
图片加载类
import java.io.file; import java.io.fileinputstream; import java.io.filenotfoundexception; import java.io.fileoutputstream; import java.io.inputstream; import java.io.outputstream; import java.net.httpurlconnection; import java.net.url; import java.util.collections; import java.util.map; import java.util.weakhashmap; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import android.content.context; import android.graphics.bitmap; import android.graphics.bitmapfactory; import android.os.handler; import android.widget.imageview; public class imageloader { /** * network time out */ private static final int time_out = 30000; /** * default picture resource */ private static final int default_bg = r.drawable.plate_list_head_bg; /** * thread pool number */ private static final int thread_num = 5; /** * memory image cache */ memorycache memorycache = new memorycache(); /** * file image cache */ filecache filecache; /** * judge image view if it is reuse */ private map<imageview, string> imageviews = collections .synchronizedmap(new weakhashmap<imageview, string>()); /** * thread pool */ executorservice executorservice; /** * handler to display images in ui thread */ handler handler = new handler(); public imageloader(context context) { filecache = new filecache(context); executorservice = executors.newfixedthreadpool(thread_num); } public void displayimage(string url, imageview imageview) { imageviews.put(imageview, url); bitmap bitmap = memorycache.get(url); if (bitmap != null) { // display image from memory cache imageview.setimagebitmap(bitmap); } else { // display image from file cache or network queuephoto(url, imageview); } } private void queuephoto(string url, imageview imageview) { phototoload phototoload = new phototoload(url, imageview); executorservice.submit(new photosloader(phototoload)); } private bitmap getbitmap(string url) { file f = filecache.getfile(url); // from file cache bitmap bmp = decodefile(f); if (bmp != null) { return bmp; } // from network try { bitmap bitmap = null; url imageurl = new url(url); httpurlconnection conn = (httpurlconnection) imageurl .openconnection(); conn.setconnecttimeout(time_out); conn.setreadtimeout(time_out); conn.setinstancefollowredirects(true); inputstream is = conn.getinputstream(); outputstream os = new fileoutputstream(f); copystream(is, os); os.close(); conn.disconnect(); bitmap = decodefile(f); return bitmap; } catch (throwable ex) { if (ex instanceof outofmemoryerror) { clearcache(); } return null; } } private void copystream(inputstream is, outputstream os) { int buffer_size = 1024; try { byte[] bytes = new byte[buffer_size]; while (true) { int count = is.read(bytes, 0, buffer_size); if (count == -1) { break; } os.write(bytes, 0, count); } } catch (exception e) { } } private bitmap decodefile(file f) { try { // todo:compress image size fileinputstream fileinputstream = new fileinputstream(f); bitmap bitmap = bitmapfactory.decodestream(fileinputstream); return bitmap; } catch (filenotfoundexception e) { return null; } } private void clearcache() { memorycache.clear(); filecache.clear(); } /** * task for the queue * * @author zhengyi.wzy * */ private class phototoload { public string url; public imageview imageview; public phototoload(string url, imageview imageview) { this.url = url; this.imageview = imageview; } } /** * asynchronous to load picture * * @author zhengyi.wzy * */ class photosloader implements runnable { phototoload phototoload; public photosloader(phototoload phototoload) { this.phototoload = phototoload; } private boolean imageviewreused(phototoload phototoload) { string tag = imageviews.get(phototoload.imageview); if (tag == null || !tag.equals(phototoload.url)) { return true; } return false; } @override public void run() { // abort current thread if image view reused if (imageviewreused(phototoload)) { return; } bitmap bitmap = getbitmap(phototoload.url); // update memory memorycache.put(phototoload.url, bitmap); if (imageviewreused(phototoload)) { return; } // don't change ui in children thread bitmapdisplayer bd = new bitmapdisplayer(bitmap, phototoload); handler.post(bd); } class bitmapdisplayer implements runnable { bitmap bitmap; phototoload phototoload; public bitmapdisplayer(bitmap bitmap, phototoload phototoload) { this.bitmap = bitmap; this.phototoload = phototoload; } @override public void run() { if (imageviewreused(phototoload)) { return; } if (bitmap != null) { phototoload.imageview.setimagebitmap(bitmap); } else { phototoload.imageview.setimageresource(default_bg); } } } } }
调用方法
imageloader imageloader = new imageloader(context); imageloader.displayimage(imageurl, imageview);
推荐阅读
-
在Android的应用中实现网络图片异步加载的方法
-
Android 自定义圆形头像CircleImageView支持加载网络图片的实现代码
-
Android 自定义圆形头像CircleImageView支持加载网络图片的实现代码
-
Android应用中实现手势控制图片缩放的完全攻略
-
Android App中实现图片异步加载的实例分享
-
Android应用中图片浏览时实现自动切换功能的方法详解
-
优雅地在Java应用中实现全局枚举处理的方法
-
Android应用中实现手势控制图片缩放的完全攻略
-
Android App中实现图片异步加载的实例分享
-
Android程序开发ListView+Json+异步网络图片加载+滚动翻页的例子(图片能缓存,图片不错乱)