标签: 性能优化android开发缓存安卓
2015-03-11 00:32 969人阅读 收藏 举报
之前在郭大神的博客看到使用LruCache算法实现图片缓存的.这里仿效他的思路,自己也写了一个. 并加入ConcurrentHashMap<String, SoftReference<Bitmap>>去实现二级缓存,因为ConcurrentHashMap是多个锁的线程安全,支持高并发.很适合这种频繁访问读取内存的操作.
下面整个思路是,使用了系统提供的LruCache类做一级缓存, 大小为运行内存的1/8,当LruCache容量要满的时候,会自动将系统移除的图片放到二级缓存中,但为了避免OOM的问题,这里将SoftReference软引用加入来,当系统快要OOM的时候会自动清除里面的图片内存,当然内存充足时就会继续保存这些二级缓存的图片.强调一点,不要用SoftReference去做一级缓存,现在的Java中垃圾回收加强了对SoftReference软引用的回收机制,它只适合临时的保存一些数据缓存,并不适合长期的(相对临时而言,并不是真正的长期).
直接上代码,拿来即用哦:
-
-
-
-
-
-
-
- public class ImageLoadManager {
-
- public enum IMAGE_LOAD_TYPE
- {
- FILE_PATH,FILE_URL,FILE_RESOURCE_ID
- }
-
- private String TAG = "ImageLoadManager...";
-
- private Context context;
-
- private Set<ImageLoadTask> taskCollection;
-
-
- final static int maxCacheSize = (int)(Runtime.getRuntime().maxMemory() / 8);
-
-
- private static ConcurrentHashMap<String, SoftReference<Bitmap>> currentHashmap
- = new ConcurrentHashMap<String, SoftReference<Bitmap>>();
-
-
-
-
-
-
-
- public ImageLoadManager(Context context)
- {
- super();
- this.context = context;
- taskCollection = new HashSet<ImageLoadManager.ImageLoadTask>();
- }
-
- private static LruCache<String, Bitmap> BitmapMemoryCache = new LruCache<String, Bitmap>(maxCacheSize)
- {
- @Override
- protected int sizeOf(String key, Bitmap value)
- {
- if(value != null)
- {
- return value.getByteCount();
-
- }
- else
- {
- return 0;
- }
- }
-
-
- @Override
- protected void entryRemoved(boolean evicted, String key,Bitmap oldValue, Bitmap newValue)
- {
- if(oldValue != null)
- {
-
- currentHashmap.put(key, new SoftReference<Bitmap>(oldValue));
- }
- }
-
- };
-
-
-
-
-
-
-
- public void setImageView(IMAGE_LOAD_TYPE loadType, int imageResourceID, ImageView imageView)
- {
- if(loadType == IMAGE_LOAD_TYPE.FILE_RESOURCE_ID)
- {
-
-
-
-
-
-
-
- try
- {
- imageView.setImageResource(imageResourceID);
- return;
- } catch (Exception e) {
- Log.e(TAG, "Can find the imageID of "+imageResourceID);
- e.printStackTrace();
- }
-
- imageView.setImageResource(R.drawable.pic_default);
- }
- }
-
-
-
-
-
-
-
- public void setImageView(IMAGE_LOAD_TYPE loadType, String imageFilePath, ImageView imageView)
- {
- if(imageFilePath == null || imageFilePath.trim().equals(""))
- {
- imageView.setImageResource(R.drawable.pic_default);
-
- }else{
- Bitmap bitmap = getBitmapFromMemoryCache(imageFilePath);
- if(bitmap != null)
- {
- imageView.setImageBitmap(bitmap);
- }
- else
- {
- imageView.setImageResource(R.drawable.pic_default);
- ImageLoadTask task = new ImageLoadTask(loadType, imageView);
- taskCollection.add(task);
- task.execute(imageFilePath);
- }
- }
- }
-
-
-
-
-
-
- public Bitmap getBitmapFromMemoryCache(String key)
- {
- try
- {
- if(BitmapMemoryCache.get(key) == null)
- {
- if(currentHashmap.get(key) != null)
- {
- return currentHashmap.get(key).get();
- }
- }
- return BitmapMemoryCache.get(key);
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- return BitmapMemoryCache.get(key);
- }
-
-
-
-
-
-
- private void addBitmapToCache(String key, Bitmap bitmap)
- {
- BitmapMemoryCache.put(key, bitmap);
- }
-
-
-
-
-
-
-
- private class ImageLoadTask extends AsyncTask<String, Void, Bitmap>
- {
- private String imagePath;
- private ImageView imageView;
- private IMAGE_LOAD_TYPE loadType;
-
- public ImageLoadTask(IMAGE_LOAD_TYPE loadType , ImageView imageView)
- {
- this.loadType = loadType;
- this.imageView = imageView;
- }
-
- @Override
- protected Bitmap doInBackground(String...params)
- {
- imagePath = params[0];
- try
- {
- if(loadType == IMAGE_LOAD_TYPE.FILE_PATH)
- {
- if(new File(imagePath).exists())
- {
- BitmapFactory.Options opts = new BitmapFactory.Options();
- opts.inSampleSize = 2;
- Bitmap bitmap = BitmapFactory.decodeFile(imagePath, opts);
-
- addBitmapToCache(imagePath, bitmap);
- return bitmap;
- }
- return null;
- }
- else if(loadType == IMAGE_LOAD_TYPE.FILE_URL)
- {
- byte[] datas = getBytesOfBitMap(imagePath);
- if(datas != null)
- {
-
-
-
- Bitmap bitmap = BitmapFactory.decodeByteArray(datas, 0, datas.length);
- addBitmapToCache(imagePath, bitmap);
- return bitmap;
- }
- return null;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- FileUtils.saveExceptionLog(e);
-
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Bitmap bitmap)
- {
- try
- {
- if(imageView != null)
- {
- if(bitmap != null)
- {
- imageView.setImageBitmap(bitmap);
- }
- else
- {
- Log.e(TAG, "The bitmap result is null...");
- }
- }
- else
- {
- Log.e(TAG, "The imageView is null...");
-
- imageView.setImageResource(R.drawable.pic_default);
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- FileUtils.saveExceptionLog(e);
- }
- }
-
-
- }
-
-
-
-
-
-
-
-
- private byte[] readStream(InputStream inStream) throws Exception{
- ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- byte[] buffer = new byte[2048];
- int len = 0;
- while( (len=inStream.read(buffer)) != -1){
- outStream.write(buffer, 0, len);
- }
- outStream.close();
- inStream.close();
- return outStream.toByteArray();
- }
-
-
-
-
-
-
- private byte[] getBytesOfBitMap(String imgUrl){
- try {
- URL url = new URL(imgUrl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(10 * 1000);
- conn.setReadTimeout(20 * 1000);
- conn.setRequestMethod("GET");
- conn.connect();
- InputStream in = conn.getInputStream();
- return readStream(in);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
-
-
-
-
-
- private boolean ifResourceIdExist(int resourceId)
- {
- try
- {
- Field field = R.drawable.class.getField(String.valueOf(resourceId));
- Integer.parseInt(field.get(null).toString());
- return true;
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
-
-
-
-
- public void cancelAllTask()
- {
- if(taskCollection != null){
- for(ImageLoadTask task : taskCollection)
- {
- task.cancel(false);
- }
- }
- }
-
-
- }
In addition, 如果需要更加完美的体验,还可以加入第三级的缓存机制, 比如将图片缓存到本地的磁盘存储空间中.但是又不想这些缓存在本地的图片被其他应用扫描到或者被用户看到怎么办? 这里有几个思路, 比如将图片用加密算法转为字符串存储,或者将图片转为自定义格式的未知文件去放在隐蔽的地方(很多应用都采取了这种方式). 这个不妨自己去尝试实现哦~