• android 网络图片双缓存


    本文转自:http://blog.csdn.net/a79412906/article/details/10180583

    Android每次加载图片很浪费时间。所以设计了一个图片缓存技术来解决每次android手机加载图片的问题

    内存的读取速度是最快的,然后是文件的读取速度,最后是网络资源的读取

    既然内存的读取时间最快,我们好好利用内存资源。将内存再分两层缓存

    强引用缓存不会轻易被回收,来保存常用数据,不常用的资源放入软引用缓存中。

    对于硬引用和软引用的介绍:

    强引用(StrongReference)
        强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

    ⑵软引用(SoftReference)

    如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存

     1,对于强引用和软引用的使用,我们首先去强引用缓存中去找图片资源,当没有发现时,就去软引用缓存中。当强引用的超额时,将最后使用的资源放入软引用缓存中,使用到软引用的资源时 ,则将资源重新放回强引用缓存池中。

     2,内存缓存池中找不到,就去文件中查找,

     

    3,再找不到就只好去网络上下载了,下载到以后,分别将资源放入文件缓存和内存缓存中

     

    Android对于InputStream流有个小bug在慢速网络的情况下可能产生中断,可以考虑重写FilterInputStream处理 skip方法来解决这个bug。 BitmapFactory类的decodeStream方法在网络超时或较慢的时候无法获取完整的数据,这里我 们通 过继承FilterInputStream类的skip方法来强制实现flush流中的数据,主要原理就是检查是否到文件末端,告诉http类是否继续。

     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;

            }

        }

     主界面读取图片

    1. public class MainActivity extends Activity {  
    2.   
    3.     private ImageMemoryCache memoryCache;  
    4.     private ImageFileCache fileCache;  
    5.     private ImageView imageView;  
    6.     @Override  
    7.     protected void onCreate(Bundle savedInstanceState) {  
    8.         super.onCreate(savedInstanceState);  
    9.         setContentView(R.layout.main);  
    10.         memoryCache=new ImageMemoryCache(this);  
    11.         fileCache=new ImageFileCache();  
    12.         imageView=(ImageView) findViewById(R.id.img);  
    13.         Bitmap b=getBitmap("http://f.hiphotos.baidu.com/album/w%3D2048/sign=7aa167f79f2f07085f052d00dd1cb999/472309f7905298228f794c7bd6ca7bcb0b46d4c4.jpg");  
    14.         imageView.setImageBitmap(b);  
    15.       
    16.           
    17.           
    18.     }  
    19.   
    20.     public Bitmap getBitmap(String url) {  
    21.         // 从内存缓存中获取图片  
    22.         Bitmap result = memoryCache.getBitmapFromCache(url);  
    23.         if (result == null) {  
    24.             // 文件缓存中获取  
    25.             result = fileCache.getImage(url);  
    26.             if (result == null) {  
    27.                 // 从网络获取  
    28.                 result = ImageGetFromHttp.downloadBitmap(url);  
    29.                 if (result != null) {  
    30.                     fileCache.saveBitmap(result, url);  
    31.                     memoryCache.addBitmapToCache(url, result);  
    32.                 }  
    33.             } else {  
    34.                 // 添加到内存缓存  
    35.                 memoryCache.addBitmapToCache(url, result);  
    36.             }  
    37.         }  
    38.         return result;  
    39.     }  
    40.   
    41. }  

     内存中读取

    1. public class ImageMemoryCache {  
    2.     /** 
    3.      * 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。 
    4.      * 硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。 
    5.      */  
    6.     private static final int SOFT_CACHE_SIZE = 15;  //软引用缓存容量  
    7.     private static LruCache<String, Bitmap> mLruCache;  //硬引用缓存  
    8.     private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;  //软引用缓存  
    9.                                                                                             
    10.     public ImageMemoryCache(Context context) {  
    11.         int memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();  
    12.         int cacheSize = 1024 * 1024 * memClass / 4;  //硬引用缓存容量,为系统可用内存的1/4  
    13.         mLruCache = new LruCache<String, Bitmap>(cacheSize) {  
    14.             @Override  
    15.             protected int sizeOf(String key, Bitmap value) {  
    16.                 if (value != null)  
    17.                     return value.getRowBytes() * value.getHeight();  
    18.                 else  
    19.                     return 0;  
    20.             }  
    21.                                                                                             
    22.             @Override  
    23.             protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {  
    24.                 if (oldValue != null)  
    25.                     // 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存  
    26.                     mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));  
    27.             }  
    28.         };  
    29.         mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(SOFT_CACHE_SIZE, 0.75f, true) {  
    30.             private static final long serialVersionUID = 6040103833179403725L;  
    31.             @Override  
    32.             protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) {  
    33.                 if (size() > SOFT_CACHE_SIZE){      
    34.                     return true;    
    35.                 }    
    36.                 return false;   
    37.             }  
    38.         };  
    39.     }  
    40.                                                                                     
    41.     /** 
    42.      * 从缓存中获取图片 
    43.      */  
    44.     public Bitmap getBitmapFromCache(String url) {  
    45.         Bitmap bitmap;  
    46.         //先从硬引用缓存中获取  
    47.         synchronized (mLruCache) {  
    48.             bitmap = mLruCache.get(url);  
    49.             if (bitmap != null) {  
    50.                 //如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除  
    51.                 mLruCache.remove(url);  
    52.                 mLruCache.put(url, bitmap);  
    53.                 return bitmap;  
    54.             }  
    55.         }  
    56.         //如果硬引用缓存中找不到,到软引用缓存中找  
    57.         synchronized (mSoftCache) {   
    58.             SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);  
    59.             if (bitmapReference != null) {  
    60.                 bitmap = bitmapReference.get();  
    61.                 if (bitmap != null) {  
    62.                     //将图片移回硬缓存  
    63.                     mLruCache.put(url, bitmap);  
    64.                     mSoftCache.remove(url);  
    65.                     return bitmap;  
    66.                 } else {  
    67.                     mSoftCache.remove(url);  
    68.                 }  
    69.             }  
    70.         }  
    71.         return null;  
    72.     }   
    73.                                                                                     
    74.     /** 
    75.      * 添加图片到缓存 
    76.      */  
    77.     public void addBitmapToCache(String url, Bitmap bitmap) {  
    78.         if (bitmap != null) {  
    79.             synchronized (mLruCache) {  
    80.                 mLruCache.put(url, bitmap);  
    81.             }  
    82.         }  
    83.     }  
    84.                                                                                     
    85.     public void clearCache() {  
    86.         mSoftCache.clear();  
    87.     }  
    88. }  
    1. public class ImageFileCache {  
    2.     private static final String CACHDIR = "ImgCach";  
    3.     private static final String WHOLESALE_CONV = ".cach";  
    4.                                                               
    5.     private static final int MB = 1024*1024;  
    6.     private static final int CACHE_SIZE = 10;  
    7.     private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;  
    8.                                                                   
    9.     public ImageFileCache() {  
    10.         //清理文件缓存  
    11.         removeCache(getDirectory());  
    12.     }  
    13.                                                                   
    14.     /** 从缓存中获取图片 **/  
    15.     public Bitmap getImage(final String url) {      
    16.         final String path = getDirectory() + "/" + convertUrlToFileName(url);  
    17.         File file = new File(path);  
    18.         if (file.exists()) {  
    19.             Bitmap bmp = BitmapFactory.decodeFile(path);  
    20.             if (bmp == null) {  
    21.                 file.delete();  
    22.             } else {  
    23.                 updateFileTime(path);  
    24.                 return bmp;  
    25.             }  
    26.         }  
    27.         return null;  
    28.     }  
    29.                                                                   
    30.     /** 将图片存入文件缓存 **/  
    31.     public void saveBitmap(Bitmap bm, String url) {  
    32.         if (bm == null) {  
    33.             return;  
    34.         }  
    35.         //判断sdcard上的空间  
    36.         if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {  
    37.             //SD空间不足  
    38.             return;  
    39.         }  
    40.         String filename = convertUrlToFileName(url);  
    41.         String dir = getDirectory();  
    42.         File dirFile = new File(dir);  
    43.         if (!dirFile.exists())  
    44.             dirFile.mkdirs();  
    45.         File file = new File(dir +"/" + filename);  
    46.         try {  
    47.             file.createNewFile();  
    48.             OutputStream outStream = new FileOutputStream(file);  
    49.             bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);  
    50.             outStream.flush();  
    51.             outStream.close();  
    52.         } catch (FileNotFoundException e) {  
    53.             Log.w("ImageFileCache", "FileNotFoundException");  
    54.         } catch (IOException e) {  
    55.             Log.w("ImageFileCache", "IOException");  
    56.         }  
    57.     }   
    58.                                                                   
    59.     /** 
    60.      * 计算存储目录下的文件大小, 
    61.      * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定 
    62.      * 那么删除40%最近没有被使用的文件 
    63.      */  
    64.     private boolean removeCache(String dirPath) {  
    65.         File dir = new File(dirPath);  
    66.         File[] files = dir.listFiles();  
    67.         if (files == null) {  
    68.             return true;  
    69.         }  
    70.         if (!android.os.Environment.getExternalStorageState().equals(  
    71.                 android.os.Environment.MEDIA_MOUNTED)) {  
    72.             return false;  
    73.         }  
    74.                                                               
    75.         int dirSize = 0;  
    76.         for (int i = 0; i < files.length; i++) {  
    77.             if (files[i].getName().contains(WHOLESALE_CONV)) {  
    78.                 dirSize += files[i].length();  
    79.             }  
    80.         }  
    81.                                                               
    82.         if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {  
    83.             int removeFactor = (int) ((0.4 * files.length) + 1);  
    84.             Arrays.sort(files, new FileLastModifSort());  
    85.             for (int i = 0; i < removeFactor; i++) {  
    86.                 if (files[i].getName().contains(WHOLESALE_CONV)) {  
    87.                     files[i].delete();  
    88.                 }  
    89.             }  
    90.         }  
    91.                                                               
    92.         if (freeSpaceOnSd() <= CACHE_SIZE) {  
    93.             return false;  
    94.         }  
    95.                                                                       
    96.         return true;  
    97.     }  
    98.                                                                   
    99.     /** 修改文件的最后修改时间 **/  
    100.     public void updateFileTime(String path) {  
    101.         File file = new File(path);  
    102.         long newModifiedTime = System.currentTimeMillis();  
    103.         file.setLastModified(newModifiedTime);  
    104.     }  
    105.                                                                   
    106.     /** 计算sdcard上的剩余空间 **/  
    107.     private int freeSpaceOnSd() {  
    108.         StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());  
    109.         double sdFreeMB = ((double)stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;  
    110.         return (int) sdFreeMB;  
    111.     }   
    112.                                                                   
    113.     /** 将url转成文件名 **/  
    114.     private String convertUrlToFileName(String url) {  
    115.         String[] strs = url.split("/");  
    116.         return strs[strs.length - 1] + WHOLESALE_CONV;  
    117.     }  
    118.                                                                   
    119.     /** 获得缓存目录 **/  
    120.     private String getDirectory() {  
    121.         String dir = getSDPath() + "/" + CACHDIR;  
    122.         return dir;  
    123.     }  
    124.                                                                   
    125.     /** 取SD卡路径 **/  
    126.     private String getSDPath() {  
    127.         File sdDir = null;  
    128.         boolean sdCardExist = Environment.getExternalStorageState().equals(  
    129.                 android.os.Environment.MEDIA_MOUNTED);  //判断sd卡是否存在  
    130.         if (sdCardExist) {  
    131.             sdDir = Environment.getExternalStorageDirectory();  //获取根目录  
    132.         }  
    133.         if (sdDir != null) {  
    134.             return sdDir.toString();  
    135.         } else {  
    136.             return "";  
    137.         }  
    138.     }   
    139.                                                               
    140.     /** 
    141.      * 根据文件的最后修改时间进行排序 
    142.      */  
    143.     private class FileLastModifSort implements Comparator<File> {  
    144.         public int compare(File arg0, File arg1) {  
    145.             if (arg0.lastModified() > arg1.lastModified()) {  
    146.                 return 1;  
    147.             } else if (arg0.lastModified() == arg1.lastModified()) {  
    148.                 return 0;  
    149.             } else {  
    150.                 return -1;  
    151.             }  
    152.         }  
    153.     }  
    154.                                                               
    155. }  


    网络下载图片

    1. public class ImageGetFromHttp {  
    2.     private static final String LOG_TAG = "ImageGetFromHttp";  
    3.                                                              
    4.     public static Bitmap downloadBitmap(String url) {  
    5.         final HttpClient client = new DefaultHttpClient();  
    6.         final HttpGet getRequest = new HttpGet(url);  
    7.                                                                  
    8.         try {  
    9.             HttpResponse response = client.execute(getRequest);  
    10.             final int statusCode = response.getStatusLine().getStatusCode();  
    11.             if (statusCode != HttpStatus.SC_OK) {  
    12.                 Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);  
    13.                 return null;  
    14.             }  
    15.                                                                      
    16.             final HttpEntity entity = response.getEntity();  
    17.             if (entity != null) {  
    18.                 InputStream inputStream = null;  
    19.                 try {  
    20.                     inputStream = entity.getContent();  
    21.                     FilterInputStream fit = new FlushedInputStream(inputStream);  
    22.                     return BitmapFactory.decodeStream(fit);  
    23.                 } finally {  
    24.                     if (inputStream != null) {  
    25.                         inputStream.close();  
    26.                         inputStream = null;  
    27.                     }  
    28.                     entity.consumeContent();  
    29.                 }  
    30.             }  
    31.         } catch (IOException e) {  
    32.             getRequest.abort();  
    33.             Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);  
    34.         } catch (IllegalStateException e) {  
    35.             getRequest.abort();  
    36.             Log.w(LOG_TAG, "Incorrect URL: " + url);  
    37.         } catch (Exception e) {  
    38.             getRequest.abort();  
    39.             Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);  
    40.         } finally {  
    41.             client.getConnectionManager().shutdown();  
    42.         }  
    43.         return null;  
    44.     }  
    45.                                                          
    46.     /* 
    47.      * An InputStream that skips the exact number of bytes provided, unless it reaches EOF. 
    48.      */  
    49.     static class FlushedInputStream extends FilterInputStream {  
    50.         public FlushedInputStream(InputStream inputStream) {  
    51.             super(inputStream);  
    52.         }  
    53.                                                          
    54.         @Override  
    55.         public long skip(long n) throws IOException {  
    56.             long totalBytesSkipped = 0L;  
    57.             while (totalBytesSkipped < n) {  
    58.                 long bytesSkipped = in.skip(n - totalBytesSkipped);  
    59.                 if (bytesSkipped == 0L) {  
    60.                     int b = read();  
    61.                     if (b < 0) {  
    62.                         break;  // we reached EOF  
    63.                     } else {  
    64.                         bytesSkipped = 1; // we read one byte  
    65.                     }  
    66.                 }  
    67.                 totalBytesSkipped += bytesSkipped;  
    68.             }  
    69.             return totalBytesSkipped;  
    70.         }  
    71.     }  
    72. }  


     权限

      1. <uses-permission android:name="android.permission.INTERNET" />  
      2.    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  • 相关阅读:
    【jQuery】清空表单内容
    【jQuery】remove()和empty()的使用
    【ajax 提交表单】多种方式的注意事项 ,serialize()的使用
    【Gson】互相转化
    yum安装nginx详解
    linux find命令
    nginx实战
    java判断是否为汉字
    分布式存储 CentOS6.5虚拟机环境搭建FastDFS-5.0.5集群(转载)
    Java应用程序实现屏幕的"拍照"
  • 原文地址:https://www.cnblogs.com/pricks/p/3921608.html
Copyright © 2020-2023  润新知