• LruCache类的相关知识以及代码实现


    一.LruCache的简单介绍

    1. Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。
    2.  * 当cache已满的时候加入新的item时,在队列尾部的item会被回收。
    3.  * 如果你cache的某个值需要明确释放,重写entryRemoved()
    4.  * 如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回。
    5.  * is limited to 4MiB of bitmaps: 默认cache大小是测量的item的数量,重写sizeof计算不同item的
    6.  *  大小。

    二.使用Lrucache来异步加载图片,防止阻塞(缓存图片)

    下面是我的一个小程序,使用得到了Lrucache,总共有三个类,代码注释也是很详细的,很适合初学者学习。主要的功能就是形成一个像瀑布的图片墙。

    在第三个类中有这个项目的设计思想。大家可以看看,共同进步,谢谢!!!

    第一个类

     1 package com.pangzaifei.falls;
     2 
     3 import android.app.Activity;
     4 import android.os.Bundle;
     5 
     6 /**
     7  * 瀑布流
     8  * 
     9  */
    10 public class Demo extends Activity {
    11     @Override
    12     protected void onCreate(Bundle savedInstanceState) {
    13         super.onCreate(savedInstanceState);
    14         setContentView(R.layout.activity_demo);
    15 
    16     }
    17 }

    第二个类

      1 package com.pangzaifei.falls;
      2 
      3 import android.graphics.Bitmap;
      4 import android.graphics.BitmapFactory;
      5 import android.graphics.BitmapFactory.Options;
      6 import android.support.v4.util.LruCache;
      7 
      8 /**
      9  * 图片资源 数据源类
     10  * 
     11  */
     12 public class Images {
     13     private static Images images;
     14     // Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。
     15     // 当cache已满的时候加入新的item时,在队列尾部的item会被回收。
     16     // 如果你cache的某个值需要明确释放,重写entryRemoved()
     17     // 如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回。
     18     // 默认cache大小是测量的item的数量,重写sizeof计算不同item的大小。
     19     private LruCache<String, Bitmap> mMemoryCache;
     20 
     21     public Images() {
     22         initLrucache();// 初始化lrucache
     23     }
     24 
     25     public static Images getInstance() {
     26         if (images == null) {
     27             images = new Images();
     28         }
     29         return images;
     30     }
     31 
     32     /**
     33      * 初始化lrucache
     34      */
     35     private void initLrucache() {
     36         // 获取应用程序最大内存
     37         long maxSize = Runtime.getRuntime().maxMemory();
     38         // 设置图片缓存大小为程序最大可用内存的1/8.
     39         int cacheSize = (int) (maxSize / 8);
     40         mMemoryCache = new LruCache<String, Bitmap>(cacheSize);
     41     }
     42 
     43     /**
     44      * 从LruCache中获取一张图片,如果不存在就返回null 从lrucache中获得key key LruCache的键,传入图片的url地址
     45      * return 对应传入的bitmap对象,或者null
     46      */
     47     public Bitmap getMemoryCache(String key) {
     48         if (mMemoryCache != null) {
     49             Bitmap bitmap = mMemoryCache.get(key);
     50             if (bitmap != null) {
     51                 return bitmap;
     52             }
     53         }
     54         return null;
     55     }
     56 
     57     /**
     58      * 将图片添加到lrucache中
     59      * 
     60      * @param key
     61      *            LruCache的键,这里传入图片的URL地址
     62      * @param bitmap
     63      *            这里指的是从网络上下载的bitmap对象。
     64      */
     65     public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
     66         if (getMemoryCache(key) == null) {
     67             mMemoryCache.put(key, bitmap);
     68         }
     69     }
     70 
     71     public static final String[] imageThumbs = new String[] {
     72             "//img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg",
     73             "//img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg",
     74             "//img-my.csdn.net/uploads/201309/01/1378037235_9280.jpg",
     75             "//img-my.csdn.net/uploads/201309/01/1378037234_3539.jpg",
     76             "//img-my.csdn.net/uploads/201309/01/1378037234_6318.jpg",
     77             "//img-my.csdn.net/uploads/201309/01/1378037194_2965.jpg",
     78             "//img-my.csdn.net/uploads/201309/01/1378037193_1687.jpg",
     79             "//img-my.csdn.net/uploads/201309/01/1378037193_1286.jpg",
     80             "//img-my.csdn.net/uploads/201309/01/1378037192_8379.jpg",
     81             "//img-my.csdn.net/uploads/201309/01/1378037178_9374.jpg",
     82             "//img-my.csdn.net/uploads/201309/01/1378037177_1254.jpg",
     83             "//img-my.csdn.net/uploads/201309/01/1378037177_6203.jpg",
     84             "//img-my.csdn.net/uploads/201309/01/1378037152_6352.jpg",
     85             "//img-my.csdn.net/uploads/201309/01/1378037151_9565.jpg",
     86             "//img-my.csdn.net/uploads/201309/01/1378037151_7904.jpg",
     87             "//img-my.csdn.net/uploads/201309/01/1378037148_7104.jpg",
     88             "//img-my.csdn.net/uploads/201309/01/1378037129_8825.jpg",
     89             "//img-my.csdn.net/uploads/201309/01/1378037128_5291.jpg",
     90             "//img-my.csdn.net/uploads/201309/01/1378037128_3531.jpg",
     91             "//img-my.csdn.net/uploads/201309/01/1378037127_1085.jpg",
     92             "//img-my.csdn.net/uploads/201309/01/1378037095_7515.jpg",
     93             "//img-my.csdn.net/uploads/201309/01/1378037094_8001.jpg",
     94             "//img-my.csdn.net/uploads/201309/01/1378037093_7168.jpg",
     95             "//img-my.csdn.net/uploads/201309/01/1378037091_4950.jpg",
     96             "//img-my.csdn.net/uploads/201308/31/1377949643_6410.jpg",
     97             "//img-my.csdn.net/uploads/201308/31/1377949642_6939.jpg",
     98             "//img-my.csdn.net/uploads/201308/31/1377949630_4505.jpg",
     99             "//img-my.csdn.net/uploads/201308/31/1377949630_4593.jpg",
    100             "//img-my.csdn.net/uploads/201308/31/1377949629_7309.jpg",
    101             "//img-my.csdn.net/uploads/201308/31/1377949629_8247.jpg",
    102             "//img-my.csdn.net/uploads/201308/31/1377949615_1986.jpg",
    103             "//img-my.csdn.net/uploads/201308/31/1377949614_8482.jpg",
    104             "//img-my.csdn.net/uploads/201308/31/1377949614_3743.jpg",
    105             "//img-my.csdn.net/uploads/201308/31/1377949614_4199.jpg",
    106             "//img-my.csdn.net/uploads/201308/31/1377949599_3416.jpg",
    107             "//img-my.csdn.net/uploads/201308/31/1377949599_5269.jpg",
    108             "//img-my.csdn.net/uploads/201308/31/1377949598_7858.jpg",
    109             "//img-my.csdn.net/uploads/201308/31/1377949598_9982.jpg",
    110             "//img-my.csdn.net/uploads/201308/31/1377949578_2770.jpg",
    111             "//img-my.csdn.net/uploads/201308/31/1377949578_8744.jpg",
    112             "//img-my.csdn.net/uploads/201308/31/1377949577_5210.jpg",
    113             "//img-my.csdn.net/uploads/201308/31/1377949577_1998.jpg",
    114             "//img-my.csdn.net/uploads/201308/31/1377949482_8813.jpg",
    115             "//img-my.csdn.net/uploads/201308/31/1377949481_6577.jpg",
    116             "//img-my.csdn.net/uploads/201308/31/1377949480_4490.jpg",
    117             "//img-my.csdn.net/uploads/201308/31/1377949455_6792.jpg",
    118             "//img-my.csdn.net/uploads/201308/31/1377949455_6345.jpg",
    119             "//img-my.csdn.net/uploads/201308/31/1377949442_4553.jpg",
    120             "//img-my.csdn.net/uploads/201308/31/1377949441_8987.jpg",
    121             "//img-my.csdn.net/uploads/201308/31/1377949441_5454.jpg",
    122             "//img-my.csdn.net/uploads/201308/31/1377949454_6367.jpg",
    123             "//img-my.csdn.net/uploads/201308/31/1377949442_4562.jpg",
    124             "//img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg",
    125             "//img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg",
    126             "//img-my.csdn.net/uploads/201309/01/1378037235_9280.jpg",
    127             "//img-my.csdn.net/uploads/201309/01/1378037234_3539.jpg",
    128             "//img-my.csdn.net/uploads/201309/01/1378037234_6318.jpg",
    129             "//img-my.csdn.net/uploads/201309/01/1378037194_2965.jpg",
    130             "//img-my.csdn.net/uploads/201309/01/1378037193_1687.jpg",
    131             "//img-my.csdn.net/uploads/201309/01/1378037193_1286.jpg",
    132             "//img-my.csdn.net/uploads/201309/01/1378037192_8379.jpg",
    133             "//img-my.csdn.net/uploads/201309/01/1378037178_9374.jpg",
    134             "//img-my.csdn.net/uploads/201309/01/1378037177_1254.jpg",
    135             "//img-my.csdn.net/uploads/201309/01/1378037177_6203.jpg",
    136             "//img-my.csdn.net/uploads/201309/01/1378037152_6352.jpg",
    137             "//img-my.csdn.net/uploads/201309/01/1378037151_9565.jpg",
    138             "//img-my.csdn.net/uploads/201309/01/1378037151_7904.jpg",
    139             "//img-my.csdn.net/uploads/201309/01/1378037148_7104.jpg",
    140             "//img-my.csdn.net/uploads/201309/01/1378037129_8825.jpg",
    141             "//img-my.csdn.net/uploads/201309/01/1378037128_5291.jpg",
    142             "//img-my.csdn.net/uploads/201309/01/1378037128_3531.jpg",
    143             "//img-my.csdn.net/uploads/201309/01/1378037127_1085.jpg",
    144             "//img-my.csdn.net/uploads/201309/01/1378037095_7515.jpg",
    145             "//img-my.csdn.net/uploads/201309/01/1378037094_8001.jpg",
    146             "//img-my.csdn.net/uploads/201309/01/1378037093_7168.jpg",
    147             "//img-my.csdn.net/uploads/201309/01/1378037091_4950.jpg",
    148             "//img-my.csdn.net/uploads/201308/31/1377949643_6410.jpg",
    149             "//img-my.csdn.net/uploads/201308/31/1377949642_6939.jpg",
    150             "//img-my.csdn.net/uploads/201308/31/1377949630_4505.jpg",
    151             "//img-my.csdn.net/uploads/201308/31/1377949630_4593.jpg",
    152             "//img-my.csdn.net/uploads/201308/31/1377949629_7309.jpg",
    153             "//img-my.csdn.net/uploads/201308/31/1377949629_8247.jpg",
    154             "//img-my.csdn.net/uploads/201308/31/1377949615_1986.jpg",
    155             "//img-my.csdn.net/uploads/201308/31/1377949614_8482.jpg",
    156             "//img-my.csdn.net/uploads/201308/31/1377949614_3743.jpg",
    157             "//img-my.csdn.net/uploads/201308/31/1377949614_4199.jpg",
    158             "//img-my.csdn.net/uploads/201308/31/1377949599_3416.jpg",
    159             "//img-my.csdn.net/uploads/201308/31/1377949599_5269.jpg",
    160             "//img-my.csdn.net/uploads/201308/31/1377949598_7858.jpg",
    161             "//img-my.csdn.net/uploads/201308/31/1377949598_9982.jpg",
    162             "//img-my.csdn.net/uploads/201308/31/1377949578_2770.jpg",
    163             "//img-my.csdn.net/uploads/201308/31/1377949578_8744.jpg",
    164             "//img-my.csdn.net/uploads/201308/31/1377949577_5210.jpg",
    165             "//img-my.csdn.net/uploads/201308/31/1377949577_1998.jpg",
    166             "//img-my.csdn.net/uploads/201308/31/1377949482_8813.jpg",
    167             "//img-my.csdn.net/uploads/201308/31/1377949481_6577.jpg",
    168             "//img-my.csdn.net/uploads/201308/31/1377949480_4490.jpg",
    169             "//img-my.csdn.net/uploads/201308/31/1377949455_6792.jpg",
    170             "//img-my.csdn.net/uploads/201308/31/1377949455_6345.jpg",
    171             "//img-my.csdn.net/uploads/201308/31/1377949442_4553.jpg",
    172             "//img-my.csdn.net/uploads/201308/31/1377949441_8987.jpg",
    173             "//img-my.csdn.net/uploads/201308/31/1377949441_5454.jpg",
    174             "//img-my.csdn.net/uploads/201308/31/1377949454_6367.jpg",
    175             "//img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg",
    176             "//img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg",
    177             "//img-my.csdn.net/uploads/201309/01/1378037235_9280.jpg",
    178             "//img-my.csdn.net/uploads/201309/01/1378037234_3539.jpg",
    179             "//img-my.csdn.net/uploads/201309/01/1378037234_6318.jpg",
    180             "//img-my.csdn.net/uploads/201309/01/1378037194_2965.jpg",
    181             "//img-my.csdn.net/uploads/201309/01/1378037193_1687.jpg",
    182             "//img-my.csdn.net/uploads/201309/01/1378037193_1286.jpg",
    183             "//img-my.csdn.net/uploads/201309/01/1378037192_8379.jpg",
    184             "//img-my.csdn.net/uploads/201309/01/1378037178_9374.jpg",
    185             "//img-my.csdn.net/uploads/201309/01/1378037177_1254.jpg",
    186             "//img-my.csdn.net/uploads/201309/01/1378037177_6203.jpg",
    187             "//img-my.csdn.net/uploads/201309/01/1378037152_6352.jpg",
    188             "//img-my.csdn.net/uploads/201309/01/1378037151_9565.jpg",
    189             "//img-my.csdn.net/uploads/201309/01/1378037151_7904.jpg",
    190             "//img-my.csdn.net/uploads/201309/01/1378037148_7104.jpg",
    191             "//img-my.csdn.net/uploads/201309/01/1378037129_8825.jpg",
    192             "//img-my.csdn.net/uploads/201309/01/1378037128_5291.jpg",
    193             "//img-my.csdn.net/uploads/201309/01/1378037128_3531.jpg",
    194             "//img-my.csdn.net/uploads/201309/01/1378037127_1085.jpg",
    195             "//img-my.csdn.net/uploads/201309/01/1378037095_7515.jpg",
    196             "//img-my.csdn.net/uploads/201309/01/1378037094_8001.jpg",
    197             "//img-my.csdn.net/uploads/201309/01/1378037093_7168.jpg",
    198             "//img-my.csdn.net/uploads/201309/01/1378037091_4950.jpg",
    199             "//img-my.csdn.net/uploads/201308/31/1377949643_6410.jpg",
    200             "//img-my.csdn.net/uploads/201308/31/1377949642_6939.jpg",
    201             "//img-my.csdn.net/uploads/201308/31/1377949630_4505.jpg",
    202             "//img-my.csdn.net/uploads/201308/31/1377949630_4593.jpg",
    203             "//img-my.csdn.net/uploads/201308/31/1377949629_7309.jpg",
    204             "//img-my.csdn.net/uploads/201308/31/1377949629_8247.jpg",
    205             "//img-my.csdn.net/uploads/201308/31/1377949615_1986.jpg",
    206             "//img-my.csdn.net/uploads/201308/31/1377949614_8482.jpg",
    207             "//img-my.csdn.net/uploads/201308/31/1377949614_3743.jpg",
    208             "//img-my.csdn.net/uploads/201308/31/1377949614_4199.jpg",
    209             "//img-my.csdn.net/uploads/201308/31/1377949599_3416.jpg",
    210             "//img-my.csdn.net/uploads/201308/31/1377949599_5269.jpg",
    211             "//img-my.csdn.net/uploads/201308/31/1377949598_7858.jpg",
    212             "//img-my.csdn.net/uploads/201308/31/1377949598_9982.jpg",
    213             "//img-my.csdn.net/uploads/201308/31/1377949578_2770.jpg",
    214             "//img-my.csdn.net/uploads/201308/31/1377949578_8744.jpg",
    215             "//img-my.csdn.net/uploads/201308/31/1377949577_5210.jpg",
    216             "//img-my.csdn.net/uploads/201308/31/1377949577_1998.jpg",
    217             "//img-my.csdn.net/uploads/201308/31/1377949482_8813.jpg",
    218             "//img-my.csdn.net/uploads/201308/31/1377949481_6577.jpg",
    219             "//img-my.csdn.net/uploads/201308/31/1377949480_4490.jpg",
    220             "//img-my.csdn.net/uploads/201308/31/1377949455_6792.jpg",
    221             "//img-my.csdn.net/uploads/201308/31/1377949455_6345.jpg",
    222             "//img-my.csdn.net/uploads/201308/31/1377949442_4553.jpg",
    223             "//img-my.csdn.net/uploads/201308/31/1377949441_8987.jpg",
    224             "//img-my.csdn.net/uploads/201308/31/1377949441_5454.jpg",
    225             "//img-my.csdn.net/uploads/201308/31/1377949454_6367.jpg",
    226             "//img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg",
    227             "//img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg",
    228             "//img-my.csdn.net/uploads/201309/01/1378037235_9280.jpg",
    229             "//img-my.csdn.net/uploads/201309/01/1378037234_3539.jpg",
    230             "//img-my.csdn.net/uploads/201309/01/1378037234_6318.jpg",
    231             "//img-my.csdn.net/uploads/201309/01/1378037194_2965.jpg",
    232             "//img-my.csdn.net/uploads/201309/01/1378037193_1687.jpg",
    233             "//img-my.csdn.net/uploads/201309/01/1378037193_1286.jpg",
    234             "//img-my.csdn.net/uploads/201309/01/1378037192_8379.jpg",
    235             "//img-my.csdn.net/uploads/201309/01/1378037178_9374.jpg",
    236             "//img-my.csdn.net/uploads/201309/01/1378037177_1254.jpg",
    237             "//img-my.csdn.net/uploads/201309/01/1378037177_6203.jpg",
    238             "//img-my.csdn.net/uploads/201309/01/1378037152_6352.jpg",
    239             "//img-my.csdn.net/uploads/201309/01/1378037151_9565.jpg",
    240             "//img-my.csdn.net/uploads/201309/01/1378037151_7904.jpg",
    241             "//img-my.csdn.net/uploads/201309/01/1378037148_7104.jpg",
    242             "//img-my.csdn.net/uploads/201309/01/1378037129_8825.jpg",
    243             "//img-my.csdn.net/uploads/201309/01/1378037128_5291.jpg",
    244             "//img-my.csdn.net/uploads/201309/01/1378037128_3531.jpg",
    245             "//img-my.csdn.net/uploads/201309/01/1378037127_1085.jpg",
    246             "//img-my.csdn.net/uploads/201309/01/1378037095_7515.jpg",
    247             "//img-my.csdn.net/uploads/201309/01/1378037094_8001.jpg",
    248             "//img-my.csdn.net/uploads/201309/01/1378037093_7168.jpg",
    249             "//img-my.csdn.net/uploads/201309/01/1378037091_4950.jpg",
    250             "//img-my.csdn.net/uploads/201308/31/1377949643_6410.jpg",
    251             "//img-my.csdn.net/uploads/201308/31/1377949642_6939.jpg",
    252             "//img-my.csdn.net/uploads/201308/31/1377949630_4505.jpg",
    253             "//img-my.csdn.net/uploads/201308/31/1377949630_4593.jpg",
    254             "//img-my.csdn.net/uploads/201308/31/1377949629_7309.jpg",
    255             "//img-my.csdn.net/uploads/201308/31/1377949629_8247.jpg",
    256             "//img-my.csdn.net/uploads/201308/31/1377949615_1986.jpg",
    257             "//img-my.csdn.net/uploads/201308/31/1377949614_8482.jpg",
    258             "//img-my.csdn.net/uploads/201308/31/1377949614_3743.jpg",
    259             "//img-my.csdn.net/uploads/201308/31/1377949614_4199.jpg",
    260             "//img-my.csdn.net/uploads/201308/31/1377949599_3416.jpg",
    261             "//img-my.csdn.net/uploads/201308/31/1377949599_5269.jpg",
    262             "//img-my.csdn.net/uploads/201308/31/1377949598_7858.jpg",
    263             "//img-my.csdn.net/uploads/201308/31/1377949598_9982.jpg",
    264             "//img-my.csdn.net/uploads/201308/31/1377949578_2770.jpg",
    265             "//img-my.csdn.net/uploads/201308/31/1377949578_8744.jpg",
    266             "//img-my.csdn.net/uploads/201308/31/1377949577_5210.jpg",
    267             "//img-my.csdn.net/uploads/201308/31/1377949577_1998.jpg",
    268             "//img-my.csdn.net/uploads/201308/31/1377949482_8813.jpg",
    269             "//img-my.csdn.net/uploads/201308/31/1377949481_6577.jpg",
    270             "//img-my.csdn.net/uploads/201308/31/1377949480_4490.jpg",
    271             "//img-my.csdn.net/uploads/201308/31/1377949455_6792.jpg",
    272             "//img-my.csdn.net/uploads/201308/31/1377949455_6345.jpg",
    273             "//img-my.csdn.net/uploads/201308/31/1377949442_4553.jpg",
    274             "//img-my.csdn.net/uploads/201308/31/1377949441_8987.jpg",
    275             "//img-my.csdn.net/uploads/201308/31/1377949441_5454.jpg",
    276             "//img-my.csdn.net/uploads/201308/31/1377949454_6367.jpg" };
    277 
    278     /**
    279      * 将大图缩放
    280      * 
    281      * @param path
    282      * @param mClolumnWidth
    283      */
    284     public Bitmap decodeSimpleBitMapFromResource(String path, int mClolumnWidth) {
    285         //第一次解析将inJustDecodeBounds设置为true,来获取图片的大小
    286         final Options options = new Options();
    287         options.inJustDecodeBounds = true;
    288         Bitmap bitmap = BitmapFactory.decodeFile(path, options);
    289         //调用方法计算insampleSize的值
    290         options.inSampleSize = decodeSimpleSize(options, mClolumnWidth);
    291         //使用获取到的inSampleSize的值
    292         options.inJustDecodeBounds = false;
    293         return BitmapFactory.decodeFile(path, options);
    294 
    295     }
    296 
    297     /**
    298      * 获得simpleSize
    299      * 
    300      * @param options
    301      * @return
    302      */
    303     private int decodeSimpleSize(Options options, int reqwidth) {
    304         //源图片的宽度
    305         int width = options.outWidth;
    306         int simplesize = 1;
    307         if (width > reqwidth) {
    308             //计算出实际宽度和目标宽度的比率
    309             simplesize = Math.round(width / reqwidth);
    310         }
    311         return simplesize;
    312     }
    313 }

    第三个类

      1 package com.pangzaifei.falls;
      2 
      3 import java.io.BufferedInputStream;
      4 import java.io.BufferedOutputStream;
      5 import java.io.File;
      6 import java.io.FileOutputStream;
      7 import java.io.IOException;
      8 import java.io.InputStream;
      9 import java.net.HttpURLConnection;
     10 import java.net.URL;
     11 import java.util.ArrayList;
     12 import java.util.HashSet;
     13 import java.util.List;
     14 import java.util.Set;
     15 
     16 import android.content.Context;
     17 import android.graphics.Bitmap;
     18 import android.graphics.BitmapFactory;
     19 import android.os.AsyncTask;
     20 import android.os.Environment;
     21 import android.os.Handler;
     22 import android.os.Message;
     23 import android.util.AttributeSet;
     24 import android.view.MotionEvent;
     25 import android.view.View;
     26 import android.view.View.OnTouchListener;
     27 import android.widget.ImageView;
     28 import android.widget.ImageView.ScaleType;
     29 import android.widget.LinearLayout;
     30 import android.widget.ScrollView;
     31 import android.widget.Toast;
     32 
     33 /**
     34  * 瀑布流类          <主要用到了LruCache类,缓存图片 >
     35  * 
     36  * 原理: 1:创建3个linearlayout,设置他们的宽度,将获得的图片压缩成和3个linearlayout一样的宽度,
     37  * 然后根据3个linearlayout的高度来判断,将bitmap添加到哪一个linearlayout中
     38  * 2:翻页处理,根据手势抬起的位置和滑动的末尾处来进行翻页
     39  * 
     40  */
     41 /*
     42 ScrollView原理
     43       视图的滚动过程,其实是在不断修改原点坐标。当手指触摸后,ScrollView会暂时拦截触摸事件,
     44       使用一个计时器。假如在计时器到点后没有发生手指移动事件,那么ScrollView发送tracking events到被点击的subView;
     45       若是在计时器到点后发生了移动事件,那么ScrollView取消tracking自己促发滚动。
     46 */
     47 /*首先还是讲一下实现原理,瀑布流的布局方式虽然看起来好像排列的很随意,其实它是有很科学的排列规则的。
     48  * 整个界面会根据屏幕的宽度划分成等宽的若干列,由于手机的屏幕不是很大,这里我们就分成三列。每当需要添加一张图片时,
     49  * 会将这张图片的宽度压缩成和列一样宽,再按照同样的压缩比例对图片的高度进行压缩,然后在这三列中找出当前高度最小的一列,
     50  * 将图片添加到这一列中。之后每当需要添加一张新图片时,都去重复上面的操作,就会形成瀑布流格局的照片墙
     51 */
     52 public class PhotoFallScrollView extends ScrollView implements OnTouchListener {
     53     /**
     54      * 记录当前已加载到第几页
     55      */
     56     private static int page;
     57     /**
     58      * 每页显示多少张图片的数量
     59      */
     60     private static final int PAGE_SIZE = 8;
     61     private Context mContext;
     62     /**
     63      * 数据源图片
     64      */
     65     private Images mImagesThoumb;
     66     /**
     67      * task请求集合
     68      */
     69     private Set<DownLoadTask> mTasks;
     70     //判断是否是第一次进入
     71     boolean isFirstEntr = true;
     72     
     73     /**三列布局
     74      * 
     75      */
     76     private LinearLayout mFirstColumn;
     77     private LinearLayout mSecondColumn;
     78     private LinearLayout mThirdColumn;
     79     //当前第一列,第二列,第三列的高度
     80     private int mFirstColumnHeight;
     81     private int mSecondColumnHeight;
     82     private int mThirdColumnHeight;
     83     /** 
     84      * 每一列的宽度 
     85      */ 
     86     private int mClolumnWidth;
     87 
     88     private long mDelay = 5;
     89     /**
     90      * 上次滑动的最后位置
     91      */
     92     private static int lastScrollY = -1;
     93 
     94     /**
     95      * 是否已加载过一次layout,这里onLayout中的初始化只需加载一次
     96      */
     97     private boolean loadOnce;
     98     /**
     99      * 存放图片的集合
    100      */
    101     private List<ImageView> mImageViewList = new ArrayList<ImageView>();
    102 
    103     public PhotoFallScrollView(Context context, AttributeSet attrs, int defStyle) {
    104         super(context, attrs, defStyle);
    105         this.mContext = context;
    106         init();
    107     }
    108 
    109     public PhotoFallScrollView(Context context, AttributeSet attrs) {
    110         super(context, attrs);
    111         this.mContext = context;
    112         init();
    113     }
    114 
    115     public PhotoFallScrollView(Context context) {
    116         super(context);
    117         this.mContext = context;
    118         init();
    119     }
    120 
    121     /**
    122      * 初始化
    123      */
    124     private void init() {
    125         mImagesThoumb = Images.getInstance();
    126         mTasks = new HashSet<DownLoadTask>();
    127         setOnTouchListener(this);
    128     }
    129 
    130     /**
    131      * 进行一些关键性的初始化操作,获取MyScrollView的高度以及得到第一列的宽度值。
    132      * 并在这里开始加载第一页的图片。 
    133      *
    134      */
    135     @Override
    136     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    137         super.onLayout(changed, l, t, r, b);
    138 
    139         // 第一次进入就加载第一页的图片
    140         if (changed && !loadOnce) {
    141             mScrollViewHeight = this.getHeight();
    142             mScrollLayout = this.getChildAt(0);//从id的值为0处开始获取
    143             mFirstColumn = (LinearLayout) findViewById(R.id.first_column);
    144             mSecondColumn = (LinearLayout) findViewById(R.id.second_column);
    145             mThirdColumn = (LinearLayout) findViewById(R.id.third_column);
    146             //获取每一列的宽度
    147             mClolumnWidth = mFirstColumn.getWidth();
    148             loadOnce = true;
    149             //开始加载下一页的图片
    150             loadMoreImages();
    151         }
    152     }
    153 
    154     /**开始加载下一页的图片,每张图片都会开启一个异步线程去下载。
    155      * 加载图片
    156      */
    157     private void loadMoreImages() {
    158         if (hashSdcard()) {
    159 
    160             // 根据页数加载图片
    161             int startIndex = page * PAGE_SIZE;
    162             int endIndex = page * PAGE_SIZE + PAGE_SIZE;
    163 
    164             if (startIndex < mImagesThoumb.imageThumbs.length) {
    165                 if (endIndex > mImagesThoumb.imageThumbs.length) {
    166                     endIndex = mImagesThoumb.imageThumbs.length;
    167                 }
    168                 for (int i = startIndex; i < endIndex; i++) {
    169                     String imageUrl = mImagesThoumb.imageThumbs[i].toString();
    170                     if (imageUrl != null && !"".equals(imageUrl)) {
    171                         //开始下载图片
    172                         downLoadData(imageUrl);
    173                     }
    174                 }
    175                 page++;
    176             } else {
    177                 Toast.makeText(mContext, "没有更多图片了", 0).show();
    178             }
    179         } else {
    180             Toast.makeText(mContext, "无sdcard", 0).show();
    181         }
    182     }
    183 
    184     /**
    185      * 下载
    186      * 
    187      * @param imageUrl
    188      */
    189     private void downLoadData(String imageUrl) {
    190         DownLoadTask task = new DownLoadTask();
    191         mTasks.add(task);
    192         //执行
    193         task.execute(imageUrl);
    194     }
    195 
    196     /**
    197      *异步下载图片
    198      */
    199     public class DownLoadTask extends AsyncTask<String, String, Bitmap> {
    200         /** 
    201          * 图片的URL地址 
    202          */
    203         private String mImageUrl;
    204 
    205         @Override
    206         protected Bitmap doInBackground(String... params) {
    207             try {
    208                 mImageUrl = params[0];
    209                 Bitmap bitmapFromMemory = mImagesThoumb
    210                         .getMemoryCache(mImageUrl);
    211                 if (bitmapFromMemory != null) {
    212                     return bitmapFromMemory;
    213                 }
    214                 if (hashSdcard()) {
    215                     Bitmap bitmap = loadImage(mImageUrl);
    216                     return bitmap;
    217                 } else {
    218                     Toast.makeText(mContext, "无sdcard,无法获取图片", 0).show();
    219                 }
    220 
    221             } catch (Exception e) {
    222                 e.printStackTrace();
    223             }
    224             return null;
    225         }
    226 
    227         @Override
    228         protected void onPostExecute(Bitmap bitmap) {
    229             super.onPostExecute(bitmap);
    230             // 展示图片
    231             if (bitmap != null) {
    232                 // 1.缩放图片
    233                 // 2.新建ImageView
    234                 // 3.找到需要的linerlayout添加imageView
    235                 float width = bitmap.getWidth();
    236                 float radio = width / mFirstColumn.getWidth();
    237                 float scaleHeight = bitmap.getHeight() / radio;
    238                 addImage(bitmap, mFirstColumn.getWidth(), scaleHeight);
    239             }
    240             mTasks.remove(this);
    241         }
    242 
    243         /** 
    244          * 向ImageView中添加一张图片 
    245          *  
    246          * @param bitmap 
    247          *            待添加的图片 
    248          * @param width 
    249          *            图片的宽度 
    250          * @param scaleHeight 
    251          *            图片的高度 
    252          */  
    253         public void addImage(Bitmap bitmap, float width, float scaleHeight) {
    254             // 生成缩放的iv
    255             ImageView iv = new ImageView(mContext);
    256             android.view.ViewGroup.LayoutParams params = new LayoutParams(
    257                     (int) width, (int) scaleHeight);
    258             iv.setLayoutParams(params);
    259             if (bitmap != null) {
    260                 // 解决默认图片有大有小的问题
    261                 iv.setScaleType(ScaleType.FIT_XY);
    262                 iv.setPadding(5, 5, 5, 5);
    263 
    264                 iv.setImageBitmap(bitmap);
    265                 iv.setTag(R.string.iamgurl, mImageUrl);
    266                 findColumnToAdd(iv, (int) scaleHeight).addView(iv);
    267                 mImageViewList.add(iv);
    268             }
    269         }
    270 
    271     }
    272 
    273     /**将图片下载到SD卡缓存起来。
    274      * @param imageUrl 图片的URL地址。 
    275      * @return
    276      * @throws IOException
    277      */
    278     private Bitmap downLoad(String imageUrl) throws IOException {
    279         BufferedInputStream bis = null;
    280         FileOutputStream fos = null;
    281         BufferedOutputStream bos = null;
    282         HttpURLConnection conn = null;
    283         File imageFile = null;
    284         try {
    285             URL url = new URL(imageUrl);
    286             conn = (HttpURLConnection) url.openConnection();
    287             conn.setReadTimeout(10000);
    288             conn.setConnectTimeout(5000);
    289             conn.setDoInput(true);
    290             conn.setDoOutput(true);
    291             InputStream is = conn.getInputStream();
    292             imageFile = new File(getImagePath(imageUrl));
    293             bis = new BufferedInputStream(is);
    294             fos = new FileOutputStream(imageFile);
    295             bos = new BufferedOutputStream(fos);
    296             int len = 0;
    297             byte[] buffer = new byte[1024];
    298             while ((len = bis.read(buffer)) != -1) {
    299                 bos.write(buffer, 0, len);
    300                 bos.flush();
    301             }
    302         } catch (Exception e) {
    303             e.printStackTrace();
    304         } finally {
    305             if (bis != null) {
    306                 bis.close();
    307             }
    308             if (bos != null) {
    309                 bos.close();
    310             }
    311             if (conn != null) {
    312                 conn.disconnect();
    313             }
    314         }
    315         // 如果imageFile不为null,将图片添加到memory中
    316         if (imageFile != null) {
    317             Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getPath());
    318             mImagesThoumb.addBitmapToMemoryCache(imageUrl, bitmap);
    319             return bitmap;
    320         }
    321         return null;
    322 
    323     }
    324 
    325    
    326     /** 
    327      * 根据传入的URL,对图片进行加载。如果这张图片已经存在于SD卡中,则直接从SD卡里读取,否则就从网络上下载。 
    328      *  
    329      * @param imageUrl 
    330      *            图片的URL地址 
    331      * @return 加载到内存的图片。 
    332      * 判断图片sdcard是否有图片,如果有就用,没有就下载
    333      */  
    334     public Bitmap loadImage(String mImageUrl) throws Exception {
    335         File file = new File(getImagePath(mImageUrl));
    336         if (!file.exists()) {
    337             downLoad(mImageUrl);
    338         }
    339 
    340         if (mImageUrl != null) {
    341             // 处理本地图片,设置大小防止oom
    342             Bitmap bitmap = mImagesThoumb.decodeSimpleBitMapFromResource(
    343                     file.getPath(), mClolumnWidth);
    344             // Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
    345             if (bitmap != null) {
    346                 mImagesThoumb.addBitmapToMemoryCache(mImageUrl, bitmap);
    347                 return bitmap;
    348             }
    349         }
    350         return null;
    351     }
    352 
    353     /** 
    354      * 找到此时应该添加图片的一列。原则就是对三列的高度进行判断,当前高度最小的一列就是应该添加的一列。 
    355      *  
    356      * @param iv 
    357      * @param imageHeight 
    358      * @return 应该添加图片的一列 
    359      */ 
    360     private LinearLayout findColumnToAdd(ImageView iv, int imageHeight) {
    361         if (mFirstColumnHeight <= mSecondColumnHeight) {
    362             if (mFirstColumnHeight <= mThirdColumnHeight) {
    363                 iv.setTag(R.string.border_top, mFirstColumnHeight);
    364                 mFirstColumnHeight += imageHeight;
    365                 iv.setTag(R.string.border_bottom, mFirstColumnHeight);
    366                 return mFirstColumn;
    367             }
    368             iv.setTag(R.string.border_top, mThirdColumnHeight);
    369             mThirdColumnHeight += imageHeight;
    370             iv.setTag(R.string.border_bottom, mThirdColumnHeight);
    371             return mThirdColumn;
    372 
    373         } else {
    374             if (mSecondColumnHeight <= mThirdColumnHeight) {
    375                 iv.setTag(R.string.border_top, mSecondColumnHeight);
    376                 mSecondColumnHeight += imageHeight;
    377                 iv.setTag(R.string.border_bottom, mSecondColumnHeight);
    378                 return mSecondColumn;
    379             }
    380             iv.setTag(R.string.border_top, mThirdColumnHeight);
    381             mThirdColumnHeight += imageHeight;
    382             iv.setTag(R.string.border_bottom, mThirdColumnHeight);
    383             return mThirdColumn;
    384         }
    385     }
    386 
    387     /**获取图片的本地存储路径。 
    388      * 获得file地址
    389      * 
    390      * @param imageUrl 图片的URL地址。
    391      * @return 图片的本地存储路径。
    392      */
    393     private String getImagePath(String imageUrl) {
    394         int lastIndexOf = imageUrl.lastIndexOf("/");
    395         String imageName = imageUrl.substring(lastIndexOf + 1);
    396         String imageDir = Environment.getExternalStorageDirectory().getPath()
    397                 + "/pangzaifei/";
    398         File file = new File(imageDir);
    399         if (!file.exists()) {
    400             file.mkdir();
    401         }
    402         String imagePath = imageDir + imageName;
    403         return imagePath;
    404     }
    405 
    406     /**判断手机是否有sd卡
    407      * 获得图片的名字
    408      * 
    409      * @param imageUrl
    410      */
    411 
    412     private boolean hashSdcard() {
    413         if (Environment.getExternalStorageState().equals(
    414                 Environment.MEDIA_MOUNTED)) {
    415             return true;
    416         }
    417         return false;
    418     }
    419 
    420     @Override
    421     /**
    422      * 当手势抬起时,开始每个5毫秒计算位置
    423      * 监听用户的触屏事件,如果用户手指离开屏幕则开始进行滚动检测。 
    424      */
    425     public boolean onTouch(View v, MotionEvent event) {
    426         if (event.getAction() == MotionEvent.ACTION_UP) {
    427             // 发送handler
    428             Message msg = mHandler.obtainMessage();
    429             msg.obj = this;
    430             mHandler.sendMessageDelayed(msg, mDelay);
    431         }
    432         return false;
    433     }
    434 
    435     /**
    436      * 在Handler中进行图片可见性检测的判断,以及加载更多图片的操作
    437      */
    438     private Handler mHandler = new Handler() {
    439 
    440         @Override
    441         public void handleMessage(Message msg) {
    442             super.handleMessage(msg);
    443             // 判断是否已经滑到了最低处,如果滑到了最低处,则加载更多页面,否则继续发送handler扫描
    444             PhotoFallScrollView scrollView = (PhotoFallScrollView) msg.obj;
    445             int scrollY = scrollView.getScrollY();
    446             //如果当前的滚动位置和上次相同,表示已停止滚动
    447             if (scrollY == lastScrollY) {
    448             // 当滚动的最底部,并且当前没有正在下载的任务时,开始加载下一页的图片  
    449                 if (mScrollViewHeight + scrollY >= mScrollLayout.getHeight()
    450                         && mTasks.isEmpty()) {
    451                     scrollView.loadMoreImages();
    452                 }
    453                 scrollView.checkVisibile();
    454             } else {
    455                 lastScrollY = scrollY;
    456                 Message message = new Message();
    457                 message.obj = scrollView;
    458                //5毫秒后在对滚动位置进行判断
    459                 mHandler.sendMessageDelayed(message, mDelay);
    460             }
    461         }
    462 
    463     };
    464     /**
    465      * MyScrollView布局的高度。
    466      */
    467     private int mScrollViewHeight;
    468     /** 
    469      * MyScrollView下的直接子布局。 
    470      */  
    471     private View mScrollLayout;
    472 
    473     /**
    474      * 遍历imageview中的每一张图片,对图片的可见性进行检测,如果图片已经离开屏幕可见范围,
    475      * 则将图片替换成一张空图
    476      * 想不可见的变为空图片
    477      */
    478     protected void checkVisibile() {
    479         if (mImageViewList != null && mImageViewList.size() > 0) {
    480             for (int i = 0; i < mImageViewList.size(); i++) {
    481                 ImageView iv = mImageViewList.get(i);
    482                 int borderTop = (Integer) iv.getTag(R.string.border_top);
    483                 int borderBottom = (Integer) iv.getTag(R.string.border_bottom);
    484                 if (borderBottom > getScrollY()
    485                         && borderTop < getScrollY() + mScrollViewHeight) {
    486                     String imageUrl = (String) iv.getTag(R.string.iamgurl);
    487                     if (imageUrl != null && !"".equals(imageUrl)) {
    488                         Bitmap bitmap = mImagesThoumb.getMemoryCache(imageUrl);
    489                         if (bitmap != null) {
    490                             iv.setImageBitmap(bitmap);
    491                         } else {
    492                             downLoadData(imageUrl);
    493                         }
    494                     }
    495                 } else {
    496                     //离开屏幕加载空图
    497                     iv.setImageResource(R.drawable.empty_photo);
    498                 }
    499 
    500             }
    501         }
    502     }
    503 }
  • 相关阅读:
    逻辑最复杂的MVVM模式实现
    剧本:博客园之天外飞仙
    本博客开始偏转方向,开始研究UDP在WCF下的实现
    Prism研究 目录
    Q & A category in Prism forums, with some answers and samples of mine.
    我眼中的SOA,以及在实际项目中的应用经验
    数据结构 C#描述 第三章 (更新)
    数据结构 C#描述 第四章
    数据结构 C#描述 第七章 (第一部分)
    数据结构 C#描述
  • 原文地址:https://www.cnblogs.com/xuanyuanzhuo-blog/p/3987638.html
Copyright © 2020-2023  润新知