Android 自定义 ImageLoader
2016-01-13 14:03
330 查看
import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; import java.util.concurrent.BlockingDeque; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingQueue; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import android.app.ProgressDialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.support.v4.util.LruCache; import android.test.UiThreadTest; import android.text.TextUtils; import android.widget.ImageView; /** * 网络图片加载 * * @author * */ public class ImageNetLoader { private static final int TIMEOUT = 30 * 1000; // protected final HashMap<String, SoftReference<Bitmap>> bitmapMap; Context mContext; BitmapFactory.Options opts = null; @SuppressWarnings("rawtypes") LruCache mMemoryCache = null; private static ImageNetLoader imageNetLoader; private BlockingQueue<FutureTask<Bitmap>> blockingqeque = new LinkedBlockingQueue<FutureTask<Bitmap>>(); private Thread loadThread = new Thread(){ public void run() { while(true){ FutureTask<Bitmap> task; try { task = blockingqeque.take(); if(task.isCancelled() ||task.isDone() ) continue; task.run(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; }; public interface LocalFileNameBuilder { public String getName(String url, String localDir); } private ImageNetLoader(Context mContext) { this.mContext = mContext; int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // 使用最大可用内存值的1/8作为缓存的大小。 int cacheSize = maxMemory / 8; mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // 重写此方法来衡量每张图片的大小,默认返回图片数量。 return bitmap.getByteCount() / 1024; } }; } public static ImageNetLoader instance(Context context) { if (imageNetLoader == null) { synchronized (ImageNetLoader.class) { if (imageNetLoader == null) { imageNetLoader = new ImageNetLoader(context); imageNetLoader.loadThread.setPriority(Thread.MIN_PRIORITY); imageNetLoader.loadThread.start(); } } } return imageNetLoader; } @SuppressWarnings("unchecked") public void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); } } @SuppressWarnings("unchecked") public Bitmap getBitmapFromMemCache(String key) { return (Bitmap) mMemoryCache.get(key); } @SuppressWarnings("unchecked") public void removeFromCache(String key) { if (mMemoryCache.get(key) != null) { mMemoryCache.remove(key); } } /** * 获取URL 并且保存到本地 * * @param urlString * @param localDir * @return * @throws ClientProtocolException * @throws IOException */ public InputStream getInputStream(String urlString, String localDir, LocalFileNameBuilder builder) throws ClientProtocolException, IOException { HttpParams params = new BasicHttpParams(); // add the timeout HttpConnectionParams.setConnectionTimeout(params, TIMEOUT); HttpConnectionParams.setSoTimeout(params, TIMEOUT); DefaultHttpClient httpClient = new DefaultHttpClient(params); HttpGet request = new HttpGet(urlString); HttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { request.abort(); return null; } InputStream in = response.getEntity().getContent(); String localPath = getLocalPath(urlString, localDir, builder); // 保存到本地 File f = new File(localPath); if (f.createNewFile()) { FileOutputStream fo = new FileOutputStream(f); BufferedInputStream bi = new BufferedInputStream(in); byte[] buffer = new byte[1024 * 10]; int len = 0; while ((len = bi.read(buffer)) > 0) { fo.write(buffer, 0, len); fo.flush(); } bi.close(); fo.close(); return new FileInputStream(f); } return in; } /** * 初始化 Bitmap参数 */ private void initOptions() { if (opts == null) { opts = new BitmapFactory.Options(); opts.inPreferredConfig = Bitmap.Config.RGB_565; opts.inSampleSize = 1; } } /** * * @param urlString * 网路路径 * @param localDir * 本地存储路径 如果不为null就保存到相应目录 否则保存到 temp目录 * * @return */ public Bitmap getBitmapByUrl(String urlString, String localDir, LocalFileNameBuilder builder) { if (TextUtils.isEmpty(urlString)) { return null; } Log.v("ImageLoader", "ImageLoader load for:"+ urlString ); try { return getBitmapFromUrl(urlString, localDir, builder); } catch (OutOfMemoryError e) { e.printStackTrace(); } catch (Exception e) { Log.v(this.getClass().getSimpleName(), "Network Exception fetchDrawable failed 1st time" + e); try { return getBitmapFromUrl(urlString, localDir, builder); } catch (OutOfMemoryError es) { es.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); Log.v(this.getClass().getSimpleName(), "Network Exception fetchDrawable failed 2nd time" + ex); } } return null; } /** * 保存网络文件到本地 * * @param urlString * @param localDir * @param builder */ public void loadUrlTolocal(String urlString, String localDir, LocalFileNameBuilder builder) { String localfile = getLocalPath(urlString, localDir, builder); File f = new File(localfile); if (f.exists() && f.canRead()) { return; } try { InputStream in = getInputStream(urlString, localDir, builder); in.close(); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 获取本地保存路径 * * @param urlString * @param localDir * @return */ private String getLocalPath(String urlString, String localDir, LocalFileNameBuilder builder) { String localPath; // 获取本地路径 if (localDir != null) { if (builder == null) { String fileName = MD5.md5Lower(urlString.substring( urlString.lastIndexOf('/'), urlString.length()) + "." + urlString.substring(urlString.lastIndexOf('.'), urlString.length())); localPath = localDir + "/" + fileName; } else { localPath = localDir + "/" + builder.getName(urlString, localDir); } } else { localPath = Config.EXTERNAL_PATH + "/temp/" + MD5.md5Lower(urlString); } return localPath; } /** * 从IN中获取bitmap * * @param in * @return */ private Bitmap getBitmapFromInputStream(InputStream in) { Bitmap bitmap = null; try { initOptions(); bitmap = BitmapFactory.decodeStream(in, null, opts); try { in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (OutOfMemoryError e) { return null; } return bitmap; } /** * get Bitmap from the input stream * * @throws IOException * @throws ClientProtocolException */ private Bitmap getBitmapFromUrl(String urlString, String localDir, LocalFileNameBuilder builder) throws ClientProtocolException, IOException { return getBitmapFromInputStream(getInputStream(urlString, localDir, builder)); } /** * 获取网络图片 不永久保存图片 * * @param urlString * @param defaultres * @param progressDialog * @param imageView1 */ public void loadBitmapOnThread(final String urlString, final int defaultres, final ProgressDialog progressDialog, final ImageView imageView1) { loadBitmapOnThread(urlString, defaultres, progressDialog, imageView1, null); } /** * 加载图片 文件名使用默认规则 默认加入到缓存中 * * @param urlString * @param defaultres * @param progressDialog * @param imageView1 * @param localDir */ public void loadBitmapOnThread(final String urlString, final int defaultres, final ProgressDialog progressDialog, final ImageView imageView1, final String localDir) { loadBitmapOnThread(urlString, defaultres, progressDialog, imageView1, localDir, null); } /** * 加载图片 默认加入到缓存中 * * @param urlString * @param defaultres * @param progressDialog * @param imageView1 * @param localDir * @param builder * 本地文件名生成规则 */ public void loadBitmapOnThread(final String urlString, final int defaultres, final ProgressDialog progressDialog, final ImageView imageView1, final String localDir, final LocalFileNameBuilder builder) { loadBitmapOnThread(urlString, defaultres, progressDialog, imageView1, localDir, builder, true); } /** * * @author popo */ class IRunnable implements Callable<Bitmap> { String url; String localDir; LocalFileNameBuilder localFileNameBuilder; boolean saveToCache; ImageView imageView; ProgressDialog progressDialog; int defaultres; public IRunnable(String url, String localDir, LocalFileNameBuilder localFileNameBuilder, boolean saveToCache, ImageView imageView, ProgressDialog progressDialog, int defaultres) { this.url = url; this.localDir = localDir; this.localFileNameBuilder = localFileNameBuilder; this.saveToCache = saveToCache; this.imageView = imageView; this.progressDialog = progressDialog; this.defaultres = defaultres; } @Override public Bitmap call() throws Exception { Bitmap drawable = null; drawable = getBitmapByUrl(url, localDir, localFileNameBuilder); if (drawable != null) { Object[] obj = new Object[] { drawable, imageView, url, defaultres, saveToCache, progressDialog }; Message message = handler.obtainMessage(1, obj); handler.sendMessage(message); } if (progressDialog != null) { progressDialog.dismiss(); } taskMaps.remove(url); return drawable; } } class Node { public IRunnable runnable; public FutureTask<Bitmap> task; } /** * ConcurrentHashMap or HashTable */ Hashtable<String, Node> taskMaps = new Hashtable<String, Node>(); /** * 加载图片 * * @param urlString * @param defaultres * @param progressDialog * @param imageView1 * @param localDir * 本地缓存目录 * @param builder * 本地文件名生成规则 * @param saveToCache * 是否 加入到缓存 */ public void loadBitmapOnThread(final String urlString, final int defaultres, final ProgressDialog progressDialog, final ImageView imageView1, final String localDir, final LocalFileNameBuilder builder, final boolean saveToCache) { if(imageView1 == null) return ; Log.v("ImageLoader"," image load for:"+urlString); // 获取以前的Tag String tag = (String) imageView1.getTag(R.id.img_tag); imageView1.setTag(R.id.img_tag, urlString); if (urlString == null || urlString.trim().equals("")) { if (imageView1.getTag(R.id.img_tag).equals(urlString)) imageView1.setImageResource(defaultres); if (progressDialog != null) { progressDialog.dismiss(); } //取消图片之前的任务 cancelTask(tag); return; } // 从缓存读取 try { Bitmap bm = getBitmapFromMemCache(urlString); if (bm != null && !bm.isRecycled() && imageView1.getTag(R.id.img_tag).equals(urlString)) { Log.v("from cache", "url:" + urlString + ",imageView:" + imageView1.toString()); imageView1.setImageBitmap(bm); if (progressDialog != null) { progressDialog.dismiss(); } //取消图片之前的任务 cancelTask(tag); return; } else { removeFromCache(urlString); if (defaultres > 0) imageView1.setImageResource(defaultres); } } catch (OutOfMemoryError e) { e.printStackTrace(); } final String localPath = getLocalPath(urlString, localDir, builder); if (localPath != null) { imageView1.setTag(R.id.localimg_tag, localPath); } File f = new File(localPath); if (f.exists() && f.canRead()) { try { FileInputStream fi = new FileInputStream(f); Bitmap b = getBitmapFromInputStream(fi); if (b != null && imageView1.getTag(R.id.localimg_tag).equals( localPath)) { Log.v("from file", "url:" + urlString + ",localPath" + localPath); if (saveToCache) { if (!b.isRecycled()) addBitmapToMemoryCache(urlString, b); } imageView1.setImageBitmap(b); //取消图片之前的任务 cancelTask(tag); return; } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (OutOfMemoryError e) { e.printStackTrace(); } } if (progressDialog != null) progressDialog.show(); //那连个地址一样怎么办捏 //同一个变相同地址 就不做任何处理了等着吧 if(tag != null && tag.equals(urlString)){ }else{ //不一样取消之前的任务 cancelTask(tag); final Node node = taskMaps.get(urlString); //之前已经有图片在下载 if(node != null ){ FutureTask<Bitmap> task = new FutureTask<Bitmap>(new Callable<Bitmap>() { @Override public Bitmap call() throws Exception { try { Bitmap drawable = node.task.get(); if (drawable != null) { Object[] obj = new Object[] { drawable, imageView1, urlString, defaultres, saveToCache, progressDialog }; Message message = handler.obtainMessage(1, obj); handler.sendMessage(message); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return null; } }); blockingqeque.offer(task); }else{ IRunnable runnable = new IRunnable(urlString, localDir, builder, saveToCache, imageView1, progressDialog, defaultres); FutureTask<Bitmap> task = new FutureTask<Bitmap>(runnable); blockingqeque.offer(task); Node n = new Node(); n.runnable = runnable; n.task = task; taskMaps.put(urlString, n); } } } /** * 取消图片任务 * @param tag */ private void cancelTask(String tag) { // 现在图片已经不需要新下载的图片了 那么取消掉吧 if(tag == null) return; Node node = taskMaps.get(tag); if (node != null) { boolean canceled = node.task.cancel(false); if (canceled && node.task.isCancelled()) { taskMaps.remove(tag); } } } final Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message message) { ImageView imageView = (ImageView) ((Object[]) message.obj)[1]; String imgpath = (String) ((Object[]) message.obj)[2]; int defaultres = (Integer) ((Object[]) message.obj)[3]; boolean saveToCache = (Boolean) ((Object[]) message.obj)[4]; if (((Object[]) message.obj)[5] != null) { ProgressDialog pd = (ProgressDialog) ((Object[]) message.obj)[5]; if (pd != null) { pd.dismiss(); } } Log.v("NETIMAGE", "url:" + imgpath + ",imageView:" + imageView); switch (message.what) { case 1: try { Bitmap bm = null; if (null == message.obj) { if (defaultres > 0) imageView.setImageResource(defaultres); } else { bm = (Bitmap) ((Object[]) message.obj)[0]; if (!bm.isRecycled()) { if (imageView != null && imageView.getTag(R.id.img_tag) != null && imageView.getTag(R.id.img_tag).equals( imgpath)) imageView.setImageBitmap(bm); removeFromCache(imgpath); addBitmapToMemoryCache(imgpath, bm); } else { if (imageView != null && defaultres > 0) imageView.setImageResource(defaultres); } } } catch (OutOfMemoryError e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } break; } } }; }
相关文章推荐
- Android异步消息处理(一)--》Handler和多线程深入
- Android ADB命令大全(通过ADB命令查看wifi密码、MAC地址、设备信息、操作文件、查看文件、日志信息、卸载、启动和安装APK等)
- android数据存储方法总结
- android 下载apk源码
- android中延迟执行某个任务
- 【Android动画】之Tween动画 (渐变、缩放、位移、旋转)
- This Handler class should be static or leaks might occur Android
- 从.NET的宠物商店到Android MVC MVP
- 阅读《Android 从入门到精通》(10)——单项选择
- android上的缓存、缓存算法和缓存框架
- Android退出应用最优雅的方式(改进版)
- [Android] Android开发优化之——对Bitmap的内存优化
- android 简单试题系统
- android studio开发中遇到的问题收集
- Android中使用log4j
- Android Studio——\\转义
- 使用Android Studio遇到的问题
- Android中EditText 的setInputType以及setRawInputType区别
- SourceTree提交AndroidManifest.xml文件
- Activity启动模式