Android网络图片缓存




获取一张图片,从三个地方进行获取,首先是内存缓存,然后是文件缓存,最后才从网络中获取。

//内存缓存

public class ImageMemoryCache {

/**

* 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。

*/

privatestatic finalint SOFT_CACHE_SIZE = 15;// 软引用缓存容量

privatestatic LruCache<String, Bitmap> mLruCache; // 硬引用缓存

privatestatic LinkedHashMap<String, SoftReference<Bitmap>>mSoftCache; // 软引用缓存


public ImageMemoryCache(Context context) {

int memClass = ((ActivityManager) context

.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();

int cacheSize = 1024 * 1024 * memClass / 4;// 硬引用缓存容量,为系统可用内存的1/4

mLruCache =new LruCache<String, Bitmap>(cacheSize) {

@Override

protectedint sizeOf(String key, Bitmap value) {

if (value !=null)

return value.getRowBytes() * value.getHeight();

else

return 0;

}


@Override

protectedvoid entryRemoved(boolean evicted, String key,

Bitmap oldValue, Bitmap newValue) {

if (oldValue !=null)

// 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存

mSoftCache.put(key,new SoftReference<Bitmap>(oldValue));

}

};

mSoftCache =new LinkedHashMap<String, SoftReference<Bitmap>>(

SOFT_CACHE_SIZE, 0.75f,true) {

privatestatic final long serialVersionUID = 6040103833179403725L;


@Override

protectedboolean removeEldestEntry(

Entry<String, SoftReference<Bitmap>> eldest) {

if (size() >SOFT_CACHE_SIZE) {

returntrue;

}

returnfalse;

}

};

}


/**

* 从缓存中获取图片

*/

public Bitmap getBitmapFromCache(String url) {

Bitmap bitmap;

// 先从硬引用缓存中获取

synchronized (mLruCache) {

bitmap = mLruCache.get(url);

if (bitmap !=null) {

// 如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除

mLruCache.remove(url);

mLruCache.put(url, bitmap);

return bitmap;

}

}

// 如果硬引用缓存中找不到,到软引用缓存中找

synchronized (mSoftCache) {

SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);

if (bitmapReference !=null) {

bitmap = bitmapReference.get();

if (bitmap !=null) {

// 将图片移回硬缓存

mLruCache.put(url, bitmap);

mSoftCache.remove(url);

return bitmap;

} else {

mSoftCache.remove(url);

}

}

}

returnnull;

}


/**

* 添加图片到缓存

*/

publicvoid addBitmapToCache(String url, Bitmap bitmap) {

if (bitmap !=null) {

synchronized (mLruCache) {

mLruCache.put(url, bitmap);

}

}

}


publicvoid clearCache() {

mSoftCache.clear();

}

}



//文件缓存,缓存到SD卡上

public class ImageFileCache {

    private static final String CACHDIR = "ImgCach";

    private static final String WHOLESALE_CONV = ".cach";

                                                            

    private static final int MB = 1024*1024;

    private static finalint CACHE_SIZE = 10;

    privatestaticfinalintFREE_SD_SPACE_NEEDED_TO_CACHE = 10;

                                                                

    public ImageFileCache() {

        //清理文件缓存

        removeCache(getDirectory());

    }

                                                                

    /** 从缓存中获取图片 **/

    public Bitmap getImage(final String url) {    

        final String path = getDirectory() +"/" + convertUrlToFileName(url);

        File file = new File(path);

        if (file.exists()) {

            Bitmap bmp = BitmapFactory.decodeFile(path);

            if (bmp == null) {

                file.delete();

            } else {

                updateFileTime(path);

                return bmp;

            }

        }

        return null;

    }

                                                                

    /** 将图片存入文件缓存 **/

    public void saveBitmap(Bitmap bm, String url) {

        if (bm == null) {

            return;

        }

        //判断sdcard上的空间

        if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {

            //SD空间不足

            return;

        }

        String filename = convertUrlToFileName(url);

       

        String dir = getDirectory();

        File dirFile = new File(dir);

        if (!dirFile.exists())

            dirFile.mkdirs();

        File file = new File(dir +"/" + filename);

        try {

            file.createNewFile();

            OutputStream outStream = new FileOutputStream(file);

            bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);

            outStream.flush();

            outStream.close();

        } catch (FileNotFoundException e) {

        

            Log.w("ImageFileCache","FileNotFoundException");

        } catch (IOException e) {

            Log.w("ImageFileCache","IOException");

        }

    } 

                                                                

    /**

     * 计算存储目录下的文件大小,

     * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定

     * 那么删除40%最近没有被使用的文件

     */

    private boolean removeCache(String dirPath) {

        File dir = new File(dirPath);

        File[] files = dir.listFiles();

        if (files == null) {

            return true;

        }

        

        if (!android.os.Environment.getExternalStorageState().equals(

                android.os.Environment.MEDIA_MOUNTED)) {

            return false;

        }

                                                            

        int dirSize = 0;

        for (int i = 0; i < files.length; i++) {

            if (files[i].getName().contains(WHOLESALE_CONV)) {

                dirSize += files[i].length();

            }

        }

                                                            

        if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {

            int removeFactor = (int) ((0.4 * files.length) + 1);

            Arrays.sort(files, new FileLastModifSort());

            for (int i = 0; i < removeFactor; i++) {

                if (files[i].getName().contains(WHOLESALE_CONV)) {

                    files[i].delete();

                }

            }

        }

                                                            

        if (freeSpaceOnSd() <= CACHE_SIZE) {

            return false;

        }

                                                                    

        return true;

    }

                                                                

    /** 修改文件的最后修改时间 **/

    public void updateFileTime(String path) {

        File file = new File(path);

        long newModifiedTime = System.currentTimeMillis();

        file.setLastModified(newModifiedTime);

    }

                                                                

    /** 计算sdcard上的剩余空间 **/

    private int freeSpaceOnSd() {

        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());

        double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) /MB;

        return (int) sdFreeMB;

    } 

                                                                

    /** 将url转成文件名 **/

    private String convertUrlToFileName(String url) {

        String[] strs = url.split("/");

        return strs[strs.length - 1] +WHOLESALE_CONV;

    }

                                                                

    /** 获得缓存目录 **/

    private String getDirectory() {

        String dir = getSDPath() + "/" +CACHDIR;

        return dir;

    }

                                                                

    /** 取SD卡路径 **/

    private String getSDPath() {

        File sdDir = null;

        boolean sdCardExist = Environment.getExternalStorageState().equals(

                android.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在

        if (sdCardExist) {

            sdDir = Environment.getExternalStorageDirectory();  //获取根目录

        }

        if (sdDir != null) {

            return sdDir.toString();

        } else {

            return "";

        }

    } 

                                                            

    /**

     * 根据文件的最后修改时间进行排序

     */

    private class FileLastModifSort implements Comparator<File> {

        public int compare(File arg0, File arg1) {

            if (arg0.lastModified() > arg1.lastModified()) {

                return 1;

            } else if (arg0.lastModified() == arg1.lastModified()) {

                return 0;

            } else {

                return -1;

            }

        }

    }

                                                            

}



//从网络加载图片

public class ImageGetFromHttp {

    private static final String LOG_TAG = "ImageGetFromHttp";

                                                           

    public static Bitmap downloadBitmap(String url) {

        final HttpClient client = new DefaultHttpClient();

        final HttpGet getRequest = new HttpGet(url);

                                                               

        try {

            HttpResponse response = client.execute(getRequest);

            final int statusCode = response.getStatusLine().getStatusCode();

            if (statusCode != HttpStatus.SC_OK) {

                Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);

                return null;

            }

                                                                   

            final HttpEntity entity = response.getEntity();

            if (entity != null) {

                InputStream inputStream = null;

                try {

                    inputStream = entity.getContent();

                    FilterInputStream fit = new FlushedInputStream(inputStream);

                    return BitmapFactory.decodeStream(fit);

                } finally {

                    if (inputStream !=null) {

                        inputStream.close();

                        inputStream = null;

                    }

                    entity.consumeContent();

                }

            }

        } catch (IOException e) {

            getRequest.abort();

            Log.w(LOG_TAG,"I/O error while retrieving bitmap from " + url, e);

        } catch (IllegalStateException e) {

            getRequest.abort();

            Log.w(LOG_TAG, "Incorrect URL: " + url);

        } catch (Exception e) {

            getRequest.abort();

            Log.w(LOG_TAG,"Error while retrieving bitmap from " + url, e);

        } finally {

            client.getConnectionManager().shutdown();

        }

        return null;

    }

                                                       

    /*

     * An InputStream that skips the exact number of bytes provided, unless it reaches EOF.

     */

    static class FlushedInputStream extends FilterInputStream {

        public FlushedInputStream(InputStream inputStream) {

            super(inputStream);

        }

                                                       

        @Override

        public long skip(long n) throws IOException {

            long totalBytesSkipped = 0L;

            while (totalBytesSkipped < n) {

                long bytesSkipped = in.skip(n - totalBytesSkipped);

                if (bytesSkipped == 0L) {

                    int b = read();

                    if (b < 0) {

                        break // we reached EOF

                    } else {

                        bytesSkipped = 1; // we read one byte

                    }

                }

                totalBytesSkipped += bytesSkipped;

            }

            return totalBytesSkipped;

        }

    }

}



//=============================获取图片========================================

/*** 获得一张图片,从三个地方获取,首先是内存缓存,然后是文件缓存,最后从网络获取 ***/

public Bitmap getBitmap(String url) {

// 从内存缓存中获取图片

Bitmap result = memoryCache.getBitmapFromCache(url);

if (result ==null) {

// 文件缓存中获取

result = fileCache.getImage(url);

if (result ==null) {

// 从网络获取

result = ImageGetFromHttp.downloadBitmap(url);

if (result !=null) {

fileCache.saveBitmap(result, url);

memoryCache.addBitmapToCache(url, result);

}

} else {

// 添加到内存缓存

memoryCache.addBitmapToCache(url, result);

}

}

return result;

你可能感兴趣的:(Android网络图片缓存)