zoukankan      html  css  js  c++  java
  • android 网络加载图片,对图片资源进行优化,并且实现内存双缓存 + 磁盘缓存

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

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

    免费培训课:http://www.jinhusns.com/Products/Curriculum/?type=xcj

     

    工程目录

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

    01./**
    02.*   实现 异步加载 和   2级缓存
    03.*/
    04.public class ImagedownActivity extends Activity {
    05. 
    06.public static String filepath;
    07.@Override
    08.public void onCreate(Bundle savedInstanceState) {
    09.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

    01.public class Myadapter extends BaseAdapter {
    02.private Context context;
    03.private String  root ="http://192.168.0.100:8080/Android_list/";
    04.private String[] URLS;
    05.private final MyImageLoader  myImageLoader = new MyImageLoader(context);;
    06. 
    07./**
    08.* adapter 初始化的时候早一堆数据
    09.* 这里我请求的是自己搭的服务器
    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(5, 5, 5, 5);
    47.}else{
    48.imageView=(ImageView)view;
    49.}
    50.myImageLoader.downLoad(URLS[position], (ImageView)imageView , context);
    51.return imageView;
    52.}
    53.}

     MyImageLoader.java

    001.public class MyImageLoader { 
    002. 
    003.//最大内存 
    004.final static int memClass = (int) Runtime.getRuntime().maxMemory();   
    005.private Context context; 
    006. 
    007.// 是否缓存到硬盘 
    008.private boolean  diskcache = true
    009. 
    010.// 定义一级 缓存的图片数 
    011.private static final int catch_num = 10
    012. 
    013.// 定义二级缓存 容器  软引用 
    014.private static ConcurrentHashMap<String, SoftReference<Bitmap>> current_hashmap = new ConcurrentHashMap<String, SoftReference<Bitmap>>(); 
    015. 
    016.// 定义一级缓存容器  强引用       (catch_num ,0.75f,true) 默认参 数                                                                                                                        2.加载因子默认        3.排序模式 true 
    017.private static LinkedHashMap<String, Bitmap> link_hashmap = new LinkedHashMap<String, Bitmap>(catch_num ,0.75f,true) { 
    018. 
    019.// 必须实现的方法 
    020.protected boolean removeEldestEntry(java.util.Map.Entry<String, Bitmap> eldest) { 
    021./** 当一级缓存中 图片数量大于 定义的数量 放入二级缓存中
    022.*/ 
    023.if (this.size() > catch_num) { 
    024.// 软连接的方法 存进二级缓存中 
    025.current_hashmap.put(eldest.getKey(), new SoftReference<Bitmap>( 
    026.eldest.getValue())); 
    027.//缓存到本地 
    028.cancheToDisk(eldest.getKey(),eldest.getValue() ); 
    029. 
    030.return true
    031.
    032.return false
    033.}; 
    034.}; 
    035. 
    036.public MyImageLoader(Context context) { 
    037. 
    038.
    039. 
    040. 
    041./**   
    042.*  外部调用此方法   进行下载图片  
    043.*/ 
    044.public void downLoad(String key , ImageView imageView,Context context){ 
    045.// 先从缓存中找   。   
    046.context = this.context; 
    047. 
    048.Bitmap bitmap = getBitmapFromCache(key); 
    049.if( null!= bitmap){  
    050.imageView.setImageBitmap(bitmap); 
    051.cancleDownload(key, imageView);         //取消下载 
    052.return
    053.}     
    054. 
    055.// 缓存中 没有  把当前的 imageView 给他 得到 task  
    056.if(cancleDownload(key, imageView)){     //没有任务进行。,。。开始下载 
    057.ImageDownloadTask task = new ImageDownloadTask(imageView); 
    058.Zhanwei_Image  zhanwei_image = new Zhanwei_Image(task); 
    059.//先把占位的图片放进去 
    060.imageView.setImageDrawable(zhanwei_image); 
    061.// task执行任务 
    062.task.execute(key);  
    063.
    064.
    065. 
    066. 
    067./** 此方法 用于优化  : 用户直接 翻到 哪个 就先加载 哪个、
    068.* @param key                - URL
    069.* @param imageView          - imageView
    070.*  core: 给当前的 imageView 得到给他下载的 task
    071.*/ 
    072. 
    073.private boolean cancleDownload(String key,ImageView imageView){ 
    074.// 给当前的 imageView 得到给他下载的 task 
    075.ImageDownloadTask task = getImageDownloadTask(imageView); 
    076.if(null != task){ 
    077.String down_key = task.key; 
    078.if( null == down_key || !down_key.equals(key)){ 
    079.task.cancel(true);        // imageview 和 url 的key不一样       取消下载    
    080.}else
    081.return false;      //正在下载:  
    082.}   
    083.
    084.return true;            //没有正在下载 
    085.
    086. 
    087. 
    088. 
    089.//  public void getThisProcessMemeryInfo() { 
    090.//        int pid = android.os.Process.myPid(); 
    091.//        android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(new int[] {pid}); 
    092.//        System.out.println("本应用当前使用了" + (float)memoryInfoArray[0].getTotalPrivateDirty() / 1024 + "mb的内存"); 
    093.//    } 
    094. 
    095. 
    096. 
    097./**
    098.* 从缓存中得到 图片的方法 1.先从一级 缓存找 linkhashmap 不是线程安全的 必须要加同步
    099.*/ 
    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.if( null != 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.if( null != imageView){   
    333.//向 imageView 里面放入 bitmap          
    334.ImageDownloadTask task = getImageDownloadTask(imageView); 
    335. 
    336./**
    337.*  判断 是不是 同一个 task( )
    338.*  如果当前这个 task  ==  imageView 里面的那个 task 就是同1个
    339.*/ 
    340.if( this == 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

    01.public class StreamTool { 
    02. 
    03.public static  byte[] read(InputStream in) throws Exception{ 
    04.ByteArrayOutputStream  out_byte = new ByteArrayOutputStream(); 
    05.byte[] buff = new byte[1024]; 
    06.int len=0
    07.while((len = in.read(buff))!= -1){ 
    08.//写到内存中  字节流 
    09.out_byte.write( buff, 0 , len); 
    10.}    
    11.out_byte.close();    
    12.// 把内存数据返回 
    13.return  out_byte.toByteArray();  
    14.
    15.}

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

    001.public class BitmapManager {
    002. 
    003./**
    004.* 按屏幕适配Bitmap
    005.*/
    006.public static Bitmap scaleBitmap(Context context, byte[] data , float percent) {
    007. 
    008.//这里我不获取了,假设是下面这个分辨率
    009.int screenWidth =   540;
    010.int screenrHeight = 950;
    011.//设置 options
    012.BitmapFactory.Options options = new BitmapFactory.Options();
    013./**
    014.*  BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds.SDK中对这个成员的说明是这样的:
    015.*  If set to true, the decoder will return null (no bitmap), but the out…
    016.*  也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你,
    017.*  它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。
    018.*/
    019.options.inJustDecodeBounds = true;
    020. 
    021.//读取
    022.Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
    023. 
    024.int imgWidth = options.outWidth;
    025.int imgHeight = options.outHeight;
    026. 
    027.//如果比你设置的宽高大  就进行缩放,
    028.if(imgWidth > screenWidth * percent || imgHeight > screenrHeight * percent) {
    029.options.inSampleSize = calculateInSampleSize(options, screenWidth, screenrHeight, percent);
    030.}
    031. 
    032. 
    033./**
    034.* If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller
    035.* to query the bitmap without having to allocate the memory for its pixels.
    036.*
    037.* 如果设置成 true,这个编码将会返回1个null , 但是那个区域仍将被设置(也就是存在),允许(调用者)去查询那个没有分配 内存的像素  bitmap
    038.*/
    039.options.inJustDecodeBounds = false;
    040. 
    041./**
    042.*  Android的Bitmap.Config给出了bitmap的一个像素所对应的存储方式,
    043.*  有RGB_565,ARGB_8888,ARGB_4444,ALPHA_8四种。RGB_565表示的是红绿蓝三色分别用5,6,5个比特来存储,
    044.*  一个像素占用了5+6+5=16个比特。ARGB_8888表示红绿蓝和半透明分别用8,8,8,8个比特来存储,
    045.*  一个像素占用了8+8+8+8=32个比特。这样的话如果图片是以RGB_8888读入的,那么占用内存的大小将是RGB_565读入方式的2倍。
    046.*  通常我们给Imagview加载图片是通过setDrawable或者在xml文件中用android:src来设置
    047.*  默认的加载图片大小的方式是以RGB_8888读入的。
    048.*
    049.*/
    050.options.inPreferredConfig = Bitmap.Config.RGB_565;
    051. 
    052./**
    053.* If this is set to true, then the resulting bitmap will allocate its pixels such that they can be purged
    054.* if the system needs to reclaim memory.
    055.*
    056.* 如果设置成 true, 这个结果bitmap 将会被分配像素,这样他们就能被 系统回收了,当系统需要回收内存的时候
    057.*/
    058.options.inPurgeable = true;
    059. 
    060./**
    061.* This field works in conjuction with inPurgeable.
    062.* 这个方法是在   inPurgeable 的基础上工作的
    063.*/
    064.options.inInputShareable = true;
    065. 
    066. 
    067.bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
    068. 
    069.System.out.println("data==="+  data.length +"  change == bitmap byte "+ bitmap.getByteCount());
    070.return bitmap;
    071.}
    072. 
    073. 
    074. 
    075.//                                                    options       reqWidth 屏幕宽      reqHeight屏幕高      你的view是屏幕的多大
    076.public static int calculateInSampleSize(BitmapFactory.Options options, int screenWidth, int screenHeight ,float percent) {
    077. 
    078.// 原始图片宽高
    079.final int height = options.outHeight;
    080.final int width = options.outWidth;
    081.// 倍数
    082.int inSampleSize = 1;
    083. 
    084.if (height > screenHeight * percent || width > screenWidth * percent) {
    085. 
    086.// 计算目标宽高与原始宽高的比值
    087.final int inSampleSize_h = Math.round((float) height / (float)( screenHeight * percent));
    088. 
    089.final int inSampleSize_w = Math.round((float) width / (float)( screenWidth * percent));
    090. 
    091.// 选择两个比值中较小的作为inSampleSize的
    092.inSampleSize = inSampleSize_h < inSampleSize_w ? inSampleSize_h : inSampleSize_w;
    093. 
    094.System.out.println("inSampleSize===="+ inSampleSize);
    095.//
    096.if(inSampleSize < 1) {
    097.inSampleSize = 1;
    098.}
    099.}
    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

     
    01.// 获取单个进程可用内存的最大值 
    02.// 方式一:使用ActivityManager服务(计量单位为M) 
    03./*int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();*/ 
    04.// 方式二:使用Runtime类(计量单位为Byte) 
    05.final static int memClass = (int) Runtime.getRuntime().maxMemory(); 
    06.// 3. 定义一级缓存容器  强引用       (catch_num /2,0.75f,true) 默认参 数                                                                                                                        2.加载因子默认        3.排序模式 true
    07.final static int  max = memClass/5;
    08. 
    09.// 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就好了。

    免费培训课:http://www.jinhusns.com/Products/Curriculum/?type=xcj

  • 相关阅读:
    如何找出阻塞的线程正在等待哪个线程
    探索Windows 10的CFG机制
    异常0xc000041d的抛出过程
    异常STATUS_FATAL_USER_CALLBACK_EXCEPTION(0xc000041d)
    VisualStudio中集成扩展调试SOS
    clr调试扩展和DAC
    WinDbg常用命令系列---sx, sxd, sxe, sxi, sxn, sxr, sx- (设置异常)
    CLR调试时的sos.dll/clr.dll/mscorwks.dll/mscordacwks.dll等动态库的版本对应
    WinDbg常用命令系列---!runaway
    WinDbg常用命令系列---!findstack
  • 原文地址:https://www.cnblogs.com/xiaoxiaojia/p/5481085.html
Copyright © 2011-2022 走看看