- 对于社交和资讯类应用,从网络获取图片并显示的功能必不可少了,异步加载图片和缓存,可以加快图片的显示和操作的流畅度,提高用户体验。
我先写了一个图片加载管理器ImageLoaderManager.java
代码如下:
- package com.xhq.common;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.UnsupportedEncodingException;
- import java.lang.ref.SoftReference;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.Map;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Environment;
- import android.support.v4.util.LruCache;
- import android.util.Log;
- public class ImageLoaderManager
- {
- private final String TAG = "ImageLoaderManager";
- private LruCache<String, Bitmap> mCache = null;
- private String cacheDir = null;
- public ImageLoaderManager(LruCache<String, Bitmap> cache)
- {
- this.mCache = cache;
- }
- public void setCacheDir(String dir)
- {
- Log.d(TAG, "缓存目录:" + dir);
- this.cacheDir = dir;
- }
- public Bitmap getBitmapFromUrl(String url)
- {
- Log.d(TAG, "getBitmapFromUrl:" + url);
- Bitmap bitmap = null;
- try
- {
- URL u = new URL(url);
- HttpURLConnection conn = (HttpURLConnection) u.openConnection();
- InputStream is = conn.getInputStream();
- bitmap = BitmapFactory.decodeStream(is);
- Log.d(TAG, "save to cache:" + url);
- mCache.put(url, bitmap);
- String fileName = getMD5Str(url);
- String filePath = this.cacheDir + fileName;
- try
- {
- FileOutputStream fos = new FileOutputStream(filePath);
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
- Log.d(TAG, "save to file:" + filePath);
- }catch(Exception e)
- {
- Log.d(TAG, " fail to save file:" + filePath);
- }
- is.close();
- conn.disconnect();
- return bitmap;
- } catch (IOException e)
- {
- e.printStackTrace();
- return null;
- }
- }
- public Bitmap getBitmapFromCache(String url)
- {
- Bitmap bitmap = null;
- synchronized (mCache)
- {
- if (mCache.get(url) != null)
- {
- bitmap = mCache.get(url);
- if (bitmap != null)
- {
- return bitmap;
- }
- }
- Log.d(TAG, "get from cache:" + url);
- bitmap = getBitmapFromFile(url);
- if (bitmap != null)
- {
- mCache.put(url, bitmap);
- }
- return bitmap;
- }
- }
- private Bitmap getBitmapFromFile(String url)
- {
- Bitmap bitmap = null;
- String fileName = getMD5Str(url);
- if (fileName == null)
- return null;
- String filePath = cacheDir + "/" + fileName;
- try
- {
- FileInputStream fis = new FileInputStream(filePath);
- bitmap = BitmapFactory.decodeStream(fis);
- } catch (FileNotFoundException e)
- {
- e.printStackTrace();
- bitmap = null;
- }
- return bitmap;
- }
- /**
- * MD5 加密
- */
- private static String getMD5Str(String str)
- {
- MessageDigest messageDigest = null;
- try
- {
- messageDigest = MessageDigest.getInstance("MD5");
- messageDigest.reset();
- messageDigest.update(str.getBytes("UTF-8"));
- } catch (NoSuchAlgorithmException e)
- {
- System.out.println("NoSuchAlgorithmException caught!");
- return null;
- } catch (UnsupportedEncodingException e)
- {
- e.printStackTrace();
- return null;
- }
- byte[] byteArray = messageDigest.digest();
- StringBuffer md5StrBuff = new StringBuffer();
- for (int i = 0; i < byteArray.length; i++)
- {
- if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
- md5StrBuff.append("0").append(
- Integer.toHexString(0xFF & byteArray[i]));
- else
- md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
- }
- return md5StrBuff.toString();
- }
- }
这个图片加载管理器功能主要是通过图片URL加载图片,分为从内存中加载图片和从网络加载图片,内存加载又分为从cache加载和从文件加载,先从cache加载,如果没有该图片就从文件加载。
从网络加载图片后会把图片保存到文件中,下次再加载相同的url图片时就不用从网络加载了。这里主要说一下LruCache 和MD5加密。
LruCache 使用了硬引用和Lru算法,Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。当cache已满的时候加入新的item时,在队列尾部的item会被回收。
这里对图片的URL进行MD5加密主要是为了更方便的在文件中保存和获取图片,因为url的和文件的路径比较相似,系统会识别不了正确的图片路径。
有了图片加载管理器,我们就进行图片的异步加载AsyncImageLoader.java
- package com.xhq.common;
- import java.util.HashSet;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import com.xhq.xweibo.R;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.os.Environment;
- import android.os.Handler;
- import android.support.v4.util.LruCache;
- import android.util.Log;
- import android.view.View;
- import android.widget.ImageView;
- public class AsyncImageLoader
- {
- private final String TAG = "AsyncImageLoader";
- private static HashSet<String> mLoadingUrlSet;
- private LruCache<String, Bitmap> mMemoryCache;
- private static ImageLoaderManager mImldmg;
- private static ExecutorService mExecutorService;
- private Handler mHandler;
- private Activity mActitity;
- public interface onLoadCompleteListener
- {
- public void onLoadSuccess(View view,Bitmap bmp, String url);
- public void onLaodFail(View view,String url);
- }
- public AsyncImageLoader(Context context)
- {
- mLoadingUrlSet = new HashSet<String>();
- mHandler = new Handler();
- int maxMemory = (int) Runtime.getRuntime().maxMemory();
- int cacheSize = maxMemory / 8;// 给LruCache分配1/8 4M
- mMemoryCache = new LruCache<String, Bitmap>(cacheSize)
- {
- // 必须重写此方法,来测量Bitmap的大小
- @Override
- protected int sizeOf(String key, Bitmap value)
- {
- return value.getRowBytes() * value.getHeight();
- }
- };
- mImldmg = new ImageLoaderManager(mMemoryCache);
- Log.d(TAG, "cachesize:" + cacheSize/1024/1024+"MB");
- startThreadPool(2);
- String appname = context.getResources().getString(R.string.app_name);
- String sdDir = "/sdcard/"+appname+"/cache/";
- String dataDir = context.getCacheDir().getAbsolutePath()+"/";
- if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
- {
- if(FileUtil.isDirExist(sdDir, true))
- {
- setCacheDir(sdDir);
- }
- }else
- {
- setCacheDir(dataDir);
- }
- }
- public void setCacheDir(String dir)
- {
- mImldmg.setCacheDir(dir);
- }
- /** 开启线程池 */
- public static void startThreadPool(int poolNum)
- {
- if (mExecutorService == null || mExecutorService.isShutdown()
- || mExecutorService.isTerminated())
- {
- mExecutorService = Executors.newFixedThreadPool((poolNum == 0) ? 1
- : poolNum);
- }
- }
- public void loadImage(final ImageView image, final String url,
- final onLoadCompleteListener onLoadComplete)
- {
- if (mLoadingUrlSet.contains(url))
- {
- Log.d(TAG, url + " is loading");
- return;
- }
- Bitmap bitmap = null;
- bitmap = mImldmg.getBitmapFromCache(url);
- if (bitmap != null)
- {
- if (onLoadComplete != null)
- {
- onLoadComplete.onLoadSuccess(image, bitmap, url);
- }
- } else
- {
- // 从网络端下载图片
- mLoadingUrlSet.add(url);
- mExecutorService.submit(new Runnable()
- {
- @Override
- public void run()
- {
- final Bitmap bitmap = mImldmg.getBitmapFromUrl(url);
- mHandler.post(new Runnable()
- {
- @Override
- public void run()
- {
- if (onLoadComplete != null)
- {
- if(bitmap != null)
- {
- onLoadComplete.onLoadSuccess(image,bitmap, url);
- }
- else
- {
- onLoadComplete.onLaodFail(image,url);
- }
- }
- mLoadingUrlSet.remove(url);
- }
- });
- }
- });
- }
- }
- }
这个图片异步加载类主要使用了线程、线程池和Handler,主要步骤:
1、设置LruCache的大小cachesize,当缓存的图片大于cachesize时,就会把队列未不的图片释放掉
2、设置图片文件的缓存路径,如果有SD卡,我们就设置缓存路径为 sdDir = "/sdcard/"+appname+"/cache/";
否则就设置缓存路径为 dataDir = context.getCacheDir().getAbsolutePath()+"/";
我们可以通过 Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) 来判定是否有SD卡
3、开启线程池,由于微博从网络加载图片是比较频繁的,每加载一张图片都和服务器建立一个连接,那么服务器的压力就很大了,所以这里运用线程池来限制连接数
线程池我们用了ExecutorService 来管理连接线程
4、最后就是在线程中加载图片了,这里运用了Thread 和Handler 来完成异步通知,当加载图片成功或者失败会通过Handler来通知UI线程更新界面
地址: http://download.csdn.net/category
版权声明:本文为博主原创文章,未经博主允许不得转载。