android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存...

经常会用到 网络文件 比如查看大图片数据 资源优化的问题,当然用开源的项目  Android-Universal-Image-Loader  或者 ignition 都是个很好的选择。

在这里把原来 写过的优化的代码直接拿出来,经过测试千张图片效果还是不错的。



工程目录:


至于 Activity 就是加载了 1个网格布局

[java]  view plain copy
  1. /** 
  2.  *   实现 异步加载 和   2级缓存 
  3.  */  
  4. public class ImagedownActivity extends Activity {  
  5.       
  6.     public static String filepath;  
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.main);  
  11.         filepath =   this.getCacheDir().getAbsolutePath();  
  12.         GridView gv=(GridView)findViewById(R.id.gridview01);  
  13.         //设置列数  
  14.         gv.setNumColumns(3);  
  15.         //配置适配器  
  16.         gv.setAdapter(new Myadapter(this));  
  17.     }  
  18.       
  19.     @Override  
  20.     protected void onDestroy() {  
  21.         // TODO Auto-generated method stub  
  22.         //activity 销毁时,清除缓存  
  23.         MyImageLoader.removeCache(filepath);  
  24.         super.onDestroy();  
  25.     }  
  26.       
  27. }  

接下来 Myadapter.java(给网格每个item塞入图片 )在生成每个 item 异步请求网络获取image
[java]  view plain copy
  1. public class Myadapter extends BaseAdapter {  
  2.     private Context context;  
  3.     private String  root ="http://192.168.0.100:8080/Android_list/";  
  4.     private String[] URLS;  
  5.     private final MyImageLoader  myImageLoader = new MyImageLoader(context);;  
  6.       
  7.     /** 
  8.      * adapter 初始化的时候早一堆数据 
  9.      * 这里我请求的是自己搭的服务器 
  10.      * @param context 
  11.      */  
  12.     public  Myadapter(Context context){  
  13.         this.context =context;  
  14.         URLS = new String[999];  
  15.         for (int i = 0; i < 999; i++) {  
  16.             URLS[i] = root + (i+1)+".jpg";  
  17.         }     
  18.     }  
  19.       
  20.       
  21.     @Override  
  22.     public int getCount() {  
  23.         return URLS.length;  
  24.     }  
  25.   
  26.     @Override  
  27.     public Object getItem(int position) {  
  28.         return URLS[position];  
  29.     }  
  30.   
  31.     @Override  
  32.     public long getItemId(int position) {  
  33.         return URLS[position].hashCode();  
  34.     }  
  35.   
  36.   
  37.       
  38.     @Override  
  39.     public View getView(int position, View view, ViewGroup parent) {  
  40.         ImageView imageView;  
  41.         if(view==null){  
  42.             imageView=new ImageView(context);  
  43.             imageView.setLayoutParams(new GridView.LayoutParams(200,190));  
  44.             imageView.setAdjustViewBounds(false);  
  45.             imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);  
  46.             imageView.setPadding(5555);  
  47.         }else{  
  48.             imageView=(ImageView)view;  
  49.         }  
  50.              myImageLoader.downLoad(URLS[position], (ImageView)imageView , context);  
  51.              return imageView;  
  52.     }  
  53. }  

MyImageLoader.java
[java]  view plain copy
  1. public class MyImageLoader {  
  2.   
  3.     //最大内存  
  4.     final static int memClass = (int) Runtime.getRuntime().maxMemory();    
  5.     private Context context;  
  6.       
  7.     // 是否缓存到硬盘  
  8.     private boolean  diskcache = true;  
  9.   
  10.     // 定义一级 缓存的图片数  
  11.     private static final int catch_num = 10;  
  12.       
  13.     // 定义二级缓存 容器  软引用  
  14.     private static ConcurrentHashMap<String, SoftReference<Bitmap>> current_hashmap = new ConcurrentHashMap<String, SoftReference<Bitmap>>();  
  15.       
  16.     // 定义一级缓存容器  强引用       (catch_num ,0.75f,true) 默认参数                                                                                                                        2.加载因子默认        3.排序模式 true  
  17.     private static LinkedHashMap<String, Bitmap> link_hashmap = new LinkedHashMap<String, Bitmap>(catch_num ,0.75f,true) {  
  18.   
  19.     // 必须实现的方法  
  20.         protected boolean removeEldestEntry(java.util.Map.Entry<String, Bitmap> eldest) {  
  21.             /** 当一级缓存中 图片数量大于 定义的数量 放入二级缓存中 
  22.              */  
  23.             if (this.size() > catch_num) {  
  24.                 // 软连接的方法 存进二级缓存中  
  25.                 current_hashmap.put(eldest.getKey(), new SoftReference<Bitmap>(  
  26.                         eldest.getValue()));  
  27.                 //缓存到本地  
  28.                 cancheToDisk(eldest.getKey(),eldest.getValue() );  
  29.                   
  30.                 return true;  
  31.             }  
  32.                return false;  
  33.         };  
  34.     };  
  35.   
  36.     public MyImageLoader(Context context) {  
  37.   
  38.     }  
  39.       
  40.       
  41.     /**    
  42.      *  外部调用此方法   进行下载图片   
  43.      */  
  44.     public void downLoad(String key , ImageView imageView,Context context){  
  45.       // 先从缓存中找   。    
  46.         context = this.context;  
  47.           
  48.         Bitmap bitmap = getBitmapFromCache(key);  
  49.         ifnull!= bitmap){   
  50.             imageView.setImageBitmap(bitmap);  
  51.             cancleDownload(key, imageView);         //取消下载  
  52.             return ;  
  53.         }      
  54.           
  55.         // 缓存中 没有  把当前的 imageView 给他 得到 task   
  56.         if(cancleDownload(key, imageView)){     //没有任务进行。,。。开始下载  
  57.             ImageDownloadTask task = new ImageDownloadTask(imageView);  
  58.             Zhanwei_Image  zhanwei_image = new Zhanwei_Image(task);  
  59.             //先把占位的图片放进去  
  60.             imageView.setImageDrawable(zhanwei_image);  
  61.             // task执行任务  
  62.             task.execute(key);   
  63.         }  
  64.     }  
  65.       
  66.       
  67.     /** 此方法 用于优化  : 用户直接 翻到 哪个 就先加载 哪个、 
  68.      * @param key                - URL 
  69.      * @param imageView          - imageView 
  70.      *  core: 给当前的 imageView 得到给他下载的 task 
  71.      */  
  72.       
  73.     private boolean cancleDownload(String key,ImageView imageView){  
  74.         // 给当前的 imageView 得到给他下载的 task  
  75.         ImageDownloadTask task = getImageDownloadTask(imageView);  
  76.         if(null != task){  
  77.             String down_key = task.key;  
  78.               ifnull == down_key || !down_key.equals(key)){  
  79.                   task.cancel(true);        // imageview 和 url 的key不一样       取消下载     
  80.               }else{  
  81.                   return false;      //正在下载:   
  82.               }    
  83.           }  
  84.              return true;            //没有正在下载  
  85.     }  
  86.       
  87.       
  88.       
  89. //  public void getThisProcessMemeryInfo() {  
  90. //        int pid = android.os.Process.myPid();  
  91. //        android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(new int[] {pid});  
  92. //        System.out.println("本应用当前使用了" + (float)memoryInfoArray[0].getTotalPrivateDirty() / 1024 + "mb的内存");  
  93. //    }  
  94.   
  95.       
  96.       
  97.     /** 
  98.      * 从缓存中得到 图片的方法 1.先从一级 缓存找 linkhashmap 不是线程安全的 必须要加同步 
  99.      */  
  100.     public Bitmap getBitmapFromCache(String key) {  
  101.          //1.先在一级缓存中找  
  102.          synchronized (link_hashmap) {  
  103.             Bitmap bitmap = link_hashmap.get(key);  
  104.             if (null != bitmap) {  
  105.                 link_hashmap.remove(key);  
  106.                 // 按照 LRU是Least Recently Used 近期最少使用算法 内存算法 就近 就 原则 放到首位  
  107.                 link_hashmap.put(key, bitmap);  
  108.                 System.out.println(" 在缓存1中找图片了 =" +key);  
  109.                 return bitmap;  
  110.             }  
  111.         }  
  112.           
  113.          // 2. 到二级 缓存找  
  114.         SoftReference<Bitmap> soft = current_hashmap.get(key);  
  115.         if (soft != null) {  
  116.             //得到 软连接 中的图片  
  117.             Bitmap soft_bitmap = soft.get();        
  118.             if (null != soft_bitmap) {  
  119.                 System.out.println(" 在缓存2中找图片了 =" +key);  
  120.                 return soft_bitmap;  
  121.             }  
  122.         } else {  
  123.             // 没有图片的话 把这个key删除  
  124.             current_hashmap.remove(key);        
  125.         }  
  126.           
  127.           
  128.         //3.都没有的话去从外部缓存文件读取  
  129.         if(diskcache){  
  130.             Bitmap bitmap = getBitmapFromFile(key);  
  131.             if(bitmap!= null){  
  132.                 link_hashmap.put(key, bitmap);   //将图片放到一级缓存首位  
  133.                 return bitmap;  
  134.             }  
  135.         }  
  136.           
  137.         return null;  
  138.     }  
  139.   
  140.       
  141.     /** 
  142.      * 缓存到本地文件 
  143.      * @param key 
  144.      * @param bitmap 
  145.      */  
  146.     public static void cancheToDisk(String key ,Bitmap bitmap ){  
  147.         //2.缓存bitmap至/data/data/packageName/cache/文件夹中  
  148.         try {  
  149.             String fileName = getMD5Str(key);  
  150.             String filePath = ImagedownActivity.filepath + "/" + fileName;  
  151.             System.out.println("缓存到本地===" + filePath);  
  152.             FileOutputStream fos = new FileOutputStream(filePath);  
  153.             bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);  
  154.               
  155.         } catch (Exception e) {  
  156.               
  157.         }  
  158.     }  
  159.       
  160.       
  161.     /** 
  162.      * 从外部文件缓存中获取bitmap 
  163.      * @param url 
  164.      * @return  
  165.      */  
  166.     private Bitmap getBitmapFromFile(String url){  
  167.         Bitmap bitmap = null;  
  168.         String fileName = getMD5Str(url);  
  169.         if(fileName == null){  
  170.             return null;  
  171.         }     
  172.         String filePath = ImagedownActivity.filepath + "/" + fileName;        
  173.         try {  
  174.             FileInputStream fis = new FileInputStream(filePath);  
  175.             bitmap = BitmapFactory.decodeStream(fis);  
  176.             System.out.println("在本地缓存中找到图片==="+ filePath);  
  177.         } catch (FileNotFoundException e) {  
  178.             System.out.println("getBitmapFromFile==="+ e.toString());  
  179.             e.printStackTrace();  
  180.             bitmap = null;  
  181.         }  
  182.         return bitmap;  
  183.     }  
  184.       
  185.       
  186.       
  187.     /** 
  188.      * 清理文件缓存 
  189.      * @param dirPath 
  190.      * @return  
  191.      */  
  192.     public static boolean removeCache(String dirPath) {  
  193.         File dir = new File(dirPath);  
  194.         File[] files = dir.listFiles();  
  195.         if(files == null || files.length == 0) {  
  196.             return true;  
  197.         }  
  198.             int dirSize = 0;  
  199.             //这里删除所有的缓存  
  200.             int all_ = (int) ( 1 * files.length + 1);  
  201.             //对files 进行排序  
  202.             Arrays.sort(files, new FileLastModifiedSort());  
  203.             for (int i = 0; i < all_ ; i++) {  
  204.                     files[i].delete();  
  205.             }  
  206.         return true;  
  207.     }  
  208.       
  209.   
  210.     /** 
  211.      * 根据文件最后修改时间进行排序 
  212.      */  
  213.     private static class FileLastModifiedSort implements Comparator<File> {  
  214.         @Override  
  215.         public int compare(File lhs, File rhs) {  
  216.             if(lhs.lastModified() > rhs.lastModified()) {  
  217.                 return 1;  
  218.             } else if(lhs.lastModified() == rhs.lastModified()) {  
  219.                 return 0;  
  220.             } else {  
  221.                 return -1;  
  222.             }  
  223.         }  
  224.     }  
  225.       
  226.   
  227.     /**   
  228.      * MD5 加密   
  229.      */     
  230.     private static String getMD5Str(String str) {     
  231.         MessageDigest messageDigest = null;     
  232.         try {     
  233.             messageDigest = MessageDigest.getInstance("MD5");     
  234.             messageDigest.reset();     
  235.             messageDigest.update(str.getBytes("UTF-8"));     
  236.         } catch (NoSuchAlgorithmException e) {     
  237.             System.out.println("NoSuchAlgorithmException caught!");     
  238.             return null;  
  239.         } catch (UnsupportedEncodingException e) {     
  240.             e.printStackTrace();  
  241.             return null;  
  242.         }     
  243.      
  244.         byte[] byteArray = messageDigest.digest();     
  245.         StringBuffer md5StrBuff = new StringBuffer();     
  246.         for (int i = 0; i < byteArray.length; i++) {                 
  247.             if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)     
  248.                 md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));     
  249.             else     
  250.                 md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));     
  251.         }     
  252.         return md5StrBuff.toString();     
  253.     }    
  254.       
  255.       
  256.     // ------------------------ 异步加载----------------------------  
  257.     /** 
  258.      *  占位的 图片 或者 颜色      用来绑定 相应的图片 
  259.      */    
  260.    class Zhanwei_Image extends ColorDrawable{  
  261.         //里面存放 相应 的异步 处理时加载好的图片 ----- 相应的 task  
  262.         private final WeakReference<ImageDownloadTask>  taskReference;  
  263.         public Zhanwei_Image(ImageDownloadTask task){     
  264.             super(Color.BLUE);  
  265.             taskReference = new WeakReference<MyImageLoader.ImageDownloadTask>(task);   
  266.         }    
  267.          // 返回去这个 task 用于比较  
  268.         public ImageDownloadTask getImageDownloadTask(){  
  269.           return taskReference.get();  
  270.         }  
  271.     }  
  272.       
  273.      
  274.     // 根据 给 的 iamgeView、 得到里面的 task  用于和当前的 task比较是不是同1个  
  275.     private ImageDownloadTask getImageDownloadTask(ImageView imageView){  
  276.         ifnull != imageView){  
  277.                 Drawable drawable = imageView.getDrawable();      
  278.             if( drawable instanceof Zhanwei_Image)  
  279.                 return ((Zhanwei_Image)drawable).getImageDownloadTask();  
  280.               
  281.         }  
  282.         return null;  
  283.     }  
  284.       
  285.       
  286.       
  287.     /** 
  288.      * 把图片 添加到缓存中 
  289.      */  
  290.     public void addBitmap(String key, Bitmap bitmap) {  
  291.         if (null != bitmap) {  
  292.             synchronized (link_hashmap) {         // 添加到一级 缓存中  
  293.                 link_hashmap.put(key, bitmap);  
  294.             }  
  295.         }  
  296.     }  
  297.       
  298.       
  299.     /** 在后台 加载每个图片 
  300.      *  第一个参数 第2个要进度条不 第三个返回结果 bitmap 
  301.      */  
  302.     class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {  
  303.   
  304.         private String key;  
  305.         private WeakReference<ImageView> imgViReference;  
  306.   
  307.         public ImageDownloadTask(ImageView imageView) {  
  308.             //imageView 传进来 。。要给哪个iamgeView加载图片  
  309.             imgViReference = new WeakReference<ImageView>(  
  310.                     imageView);  
  311.         }  
  312.   
  313.         @Override  
  314.         protected Bitmap doInBackground(String... params){  
  315.             key = params[0];  
  316.             //调用下载函数 根据 url 下载        
  317.             return downloadBitmap(key);  
  318.         }  
  319.   
  320.         @Override  
  321.         protected void onPostExecute(Bitmap result) {  
  322.             if(isCancelled()){  
  323.                 result = null;  
  324.             }  
  325.               
  326.             System.out.println("result=="+ result.getByteCount()+"---memClassmemery="+memClass);  
  327.               
  328.             if(null!= result){  
  329.                 //保存到缓存中  
  330.                    addBitmap(key, result);  
  331.                    ImageView  imageView = imgViReference.get();  
  332.                    ifnull != imageView){    
  333.                   //向 imageView 里面放入 bitmap           
  334.                         ImageDownloadTask task = getImageDownloadTask(imageView);  
  335.                           
  336.                    /** 
  337.                     *  判断 是不是 同一个 task( ) 
  338.                     *  如果当前这个 task  ==  imageView 里面的那个 task 就是同1个 
  339.                     */  
  340.                     ifthis == task ){  
  341.                          imageView.setImageBitmap(result);  
  342.                            
  343.                      }  
  344.                 }  
  345.             }  
  346.         }  
  347.     }  
  348.   
  349.       
  350.     /** 
  351.      * 连接网络 客户端 下载图片 
  352.      */  
  353.     private Bitmap downloadBitmap(String url) {  
  354.        
  355.         final HttpClient client = AndroidHttpClient.newInstance("Android");  
  356.         final HttpGet getRequest = new HttpGet(url);   
  357.         try {  
  358.             HttpResponse response = client.execute(getRequest);  
  359.             final int statusCode = response.getStatusLine().getStatusCode();  
  360.               
  361.             if (statusCode != HttpStatus.SC_OK) {  
  362.                   
  363.                 Log.w("ImageDownloader""Error " + statusCode + " while retrieving bitmap from " + url);  
  364.                 return null;  
  365.             }  
  366.   
  367.             final HttpEntity entity = response.getEntity();  
  368.             if (entity != null) {  
  369.                 InputStream inputStream = null;  
  370.                 try {  
  371.                       
  372.                     inputStream = entity.getContent();                   
  373.                     /** 
  374.                      *  1.没有压缩直接将生成的bitmap返回去 
  375.                      */  
  376. //                  return BitmapFactory.decodeStream(inputStream);  
  377.                       
  378.                    /** 
  379.                     *  2.得到data后在这里把图片进行压缩 
  380.                     */  
  381.                      byte[] data = StreamTool.read(inputStream);   
  382.                      return  BitmapManager.scaleBitmap(context, data, 0.3f);  
  383. //                   return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));  
  384.                 } finally {  
  385.                     if (inputStream != null) {  
  386.                         inputStream.close();  
  387.                     }  
  388.                     entity.consumeContent();  
  389.                 }  
  390.             }  
  391.         } catch (IOException e) {  
  392.             getRequest.abort();  
  393.         } catch (IllegalStateException e) {  
  394.             getRequest.abort();  
  395.         } catch (Exception e) {  
  396.             getRequest.abort();  
  397.         } finally {  
  398.             if ((client instanceof AndroidHttpClient)) {  
  399.                 ((AndroidHttpClient) client).close();  
  400.             }  
  401.         }  
  402.         return null;  
  403.     }  
  404.   
  405. }  

StreamTool.java

[java]  view plain copy
  1. public class StreamTool {  
  2.       
  3.     public static  byte[] read(InputStream in) throws Exception{  
  4.         ByteArrayOutputStream  out_byte = new ByteArrayOutputStream();  
  5.         byte[] buff = new byte[1024];  
  6.         int len=0;  
  7.         while((len = in.read(buff))!= -1){  
  8.              //写到内存中  字节流  
  9.             out_byte.write( buff, 0 , len);  
  10.         }     
  11.         out_byte.close();     
  12.         // 把内存数据返回  
  13.         return  out_byte.toByteArray();   
  14.     }  
  15. }  


BitmapManager.java ( 这个类里面对 网络资源的图片 进行了优化)

[java]  view plain copy
  1. public class BitmapManager {  
  2.       
  3.     /** 
  4.      * 按屏幕适配Bitmap 
  5.      */  
  6.     public static Bitmap scaleBitmap(Context context, byte[] data , float percent) {  
  7.   
  8.       //这里我不获取了,假设是下面这个分辨率  
  9.           int screenWidth =   540;  
  10.       int screenrHeight = 950;  
  11.         //设置 options  
  12.         BitmapFactory.Options options = new BitmapFactory.Options();  
  13.         /** 
  14.          *  BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds.SDK中对这个成员的说明是这样的: 
  15.          *  If set to true, the decoder will return null (no bitmap), but the out… 
  16.          *  也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你, 
  17.          *  它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。 
  18.          */  
  19.         options.inJustDecodeBounds = true;  
  20.     
  21.         //读取  
  22.         Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);  
  23.           
  24.         int imgWidth = options.outWidth;  
  25.         int imgHeight = options.outHeight;  
  26.   
  27.         //如果比你设置的宽高大  就进行缩放,  
  28.         if(imgWidth > screenWidth * percent || imgHeight > screenrHeight * percent) {  
  29.             options.inSampleSize = calculateInSampleSize(options, screenWidth, screenrHeight, percent);  
  30.         }  
  31.           
  32.           
  33.         /** 
  34.          * If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller  
  35.          * to query the bitmap without having to allocate the memory for its pixels. 
  36.          *  
  37.          * 如果设置成 true,这个编码将会返回1个null , 但是那个区域仍将被设置(也就是存在),允许(调用者)去查询那个没有分配 内存的像素  bitmap  
  38.          */  
  39.         options.inJustDecodeBounds = false;  
  40.          
  41.         /** 
  42.          *  Android的Bitmap.Config给出了bitmap的一个像素所对应的存储方式, 
  43.          *  有RGB_565,ARGB_8888,ARGB_4444,ALPHA_8四种。RGB_565表示的是红绿蓝三色分别用5,6,5个比特来存储, 
  44.          *  一个像素占用了5+6+5=16个比特。ARGB_8888表示红绿蓝和半透明分别用8,8,8,8个比特来存储, 
  45.          *  一个像素占用了8+8+8+8=32个比特。这样的话如果图片是以RGB_8888读入的,那么占用内存的大小将是RGB_565读入方式的2倍。 
  46.          *  通常我们给Imagview加载图片是通过setDrawable或者在xml文件中用android:src来设置 
  47.          *  默认的加载图片大小的方式是以RGB_8888读入的。 
  48.          *  
  49.          */  
  50.         options.inPreferredConfig = Bitmap.Config.RGB_565;  
  51.           
  52.         /** 
  53.          * If this is set to true, then the resulting bitmap will allocate its pixels such that they can be purged  
  54.          * if the system needs to reclaim memory. 
  55.          *  
  56.          * 如果设置成 true, 这个结果bitmap 将会被分配像素,这样他们就能被 系统回收了,当系统需要回收内存的时候 
  57.          */  
  58.         options.inPurgeable = true;  
  59.           
  60.         /** 
  61.          * This field works in conjuction with inPurgeable. 
  62.          * 这个方法是在   inPurgeable 的基础上工作的 
  63.          */  
  64.         options.inInputShareable = true;  
  65.           
  66.       
  67.         bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);  
  68.           
  69.         System.out.println("data==="+  data.length +"  change == bitmap byte "+ bitmap.getByteCount());  
  70.         return bitmap;  
  71.     }  
  72.       
  73.       
  74.       
  75.     //                                                    options       reqWidth 屏幕宽      reqHeight屏幕高      你的view是屏幕的多大  
  76.     public static int calculateInSampleSize(BitmapFactory.Options options, int screenWidth, int screenHeight ,float percent) {  
  77.           
  78.         // 原始图片宽高  
  79.         final int height = options.outHeight;  
  80.         final int width = options.outWidth;  
  81.         // 倍数  
  82.         int inSampleSize = 1;  
  83.     
  84.         if (height > screenHeight * percent || width > screenWidth * percent) {  
  85.               
  86.             // 计算目标宽高与原始宽高的比值  
  87.             final int inSampleSize_h = Math.round((float) height / (float)( screenHeight * percent));  
  88.               
  89.             final int inSampleSize_w = Math.round((float) width / (float)( screenWidth * percent));  
  90.                   
  91.             // 选择两个比值中较小的作为inSampleSize的  
  92.             inSampleSize = inSampleSize_h < inSampleSize_w ? inSampleSize_h : inSampleSize_w;  
  93.              
  94.             System.out.println("inSampleSize===="+ inSampleSize);  
  95.             //   
  96.             if(inSampleSize < 1) {  
  97.                 inSampleSize = 1;  
  98.             }  
  99.         }  
  100.        //简单说这个数字就是 缩小为原来的几倍,根据你的image需要占屏幕多大动态算的(比如你用的权重设置layout)  
  101.         return inSampleSize;  
  102.     }  
  103. }  

这个是代码输出的最多给这个进程分配的内存 128M


可以看到我上面的bitmapManager 里面有个   options.inPreferredConfig   注释写的很清楚,可以上去看一下,接下来贴几种格式的效果图

rgb565  和  argb_444  所占的内存              (54000)


看一下 argb_8888                    (  108000)


当然可能仔细看的人会看到我一开始截的 鸣人的效果图 上半部分 和 下半部分的颜色会有点问题。上面的rgb_565 生成的,和原图色彩可能会有点出入。

但是内存真心少了一半,所以各种取舍就看个人了,代码注释都谢的很清楚了。


至于 : MyImageLoaderLru.java  其实就是    MyImageLoader.java

先贴出代码不同地方的代码 : 就是在强引用的地方  把  LinkedHashMap 换成了 LruCache

[java]  view plain copy
  1.  // 获取单个进程可用内存的最大值    
  2.     // 方式一:使用ActivityManager服务(计量单位为M)    
  3.        /*int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();*/    
  4.     // 方式二:使用Runtime类(计量单位为Byte)    
  5.      final static int memClass = (int) Runtime.getRuntime().maxMemory();    
  6.  // 3. 定义一级缓存容器  强引用       (catch_num /2,0.75f,true) 默认参数                                                                                                                        2.加载因子默认        3.排序模式 true  
  7.   final static int  max = memClass/5;  
  8.       
  9.   // LruCache 用强引用将  图片放入     LinkedHashMap   
  10.   private static LruCache<String, Bitmap> lrucache = new LruCache<String, Bitmap>(max) {  
  11.       protected int sizeOf(String key, Bitmap value) {    
  12.              if(value != null) {    
  13.                  // 计算存储bitmap所占用的字节数    
  14.                  return value.getRowBytes() * value.getHeight();    
  15.              } else {    
  16.                  return 0;    
  17.              }    
  18.          }    
  19.              
  20.          @Override    
  21.          protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {    
  22.              if(oldValue != null) {    
  23.                  // 当硬引用缓存容量已满时,会使用LRU算法将最近没有被使用的图片转入软引用缓存    
  24.               current_hashmap.put(key, new SoftReference<Bitmap>(oldValue));    
  25.              }    
  26.          }    
  27. };  


1. 强引用:LruCache 后面再说,其实他内的内部封装的就是1个 LinkedHashMap 。LinkedHashMap 是线程不安全的,所以上面都会用到同步。

2. 软引用:ConcurrentHashMap 是线程安全的,并且支持高并发很有效率,这个后面也会说到,为什么要用 软引用 SoftReference,这个是在系统将要oom时,就会回收

                    软引用的对象资源,所以才会用到他,防止程序出异常 。

3. 磁盘缓存: 这个经常会看到网易新闻等,应用有些界面你看了很多图片,往上翻很多, 其实没有再次访问网络,会将部分image缓存在sdcard里。

4. 其中1个优化: 当比如用户快速滑动到 最底部,其实是最先加载显示给用户的部分的内容的,这样就是用户看到哪加载哪,1个是快,1个是避免资源浪费。


原理: 当用户进入界面加载图片 ,首先会从1级缓存强引用中找,找不到回去2级缓存软引用中找,找不到再去sdcard中找,再找不到才会去请求网络加载资源。

            当然sdcard的缓存 看个人需求是否需要。


注: android 4.0 后 对 SoftReference 的回收机制进行了改变,所以你是可以不用 2级缓存的,直接去掉就好了。

          只要控制好你的 lrucache 或者 linkedhashmap就好了。

转载于:https://my.oschina.net/u/266323/blog/179360

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值