android项目开发准备工作

来源:互联网 发布:学车宝模拟驾驶软件 编辑:程序博客网 时间:2024/06/07 06:04

android项目开发准备工作

代码下载请移步:

https://github.com/suzeyinhappyboy?tab=repositories

1:常用工具类创建

举例:

public static void showToast(Context context, CharSequence text, int duration) {
if(mToast == null) {
mToast = Toast.makeText(context, text, duration);
} else {
mToast.setText(text);
mToast.setDuration(duration);
}
mToast.show();
}

1.下载,比如图片,文件。
2.将下载的文件进行解压。
3.请求服务器,比如说上传登陆信息,更新某些数据,又或者上传头像文件。
4.从文件系统中选择要操作的文件(图片,拍照,视频,拍摄视频)。
5.有时候也需要爬取某些网页数据。
6.存储一些配置信息
7.播放视频
8.再有一个特殊需求就是关乎Android程序UI设计,图标是个很麻烦的问题。每次都难以找到合适的Android 设计UI。


随后,我将很有针对性的推荐一些功能库,来简化上面的问题。
1. afinal :  afinal 是一个很方便的工具库。 GitHub    作者博客 (注:国人项目哟) 一行代码就可以对数据库进行增删改查。  
完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。 
轻松实现Android上传文件,POST数据,下载文件(支持断点续传,随时停止下载任务 或者 开始任务)。 
一行代码 加载网络图片。 


2. android-async-http : Android下的异步HTTP库。 GitHub     文档   PS:作者的GitHub值得关注。 发送异步http请求,并且可在回调函数中处理返回响应Response。 
http请求在thread线程,不会阻塞UI线程。
请求使用线程池(ThreadPool)实现,优化了并发的资源使用。
支持Multipart 文件上传。
如果Request请求失败,会自动请求。
支持Json解码。
支持存储Cookies到Preference中。
支持gzip处理Request以及Response。
整个库只有19KB。
 
3. http-requests : Java http请求库,设计的很优雅的一个库,推荐。  GitHub 
4. async-http-client : Android下的异步 Http 和 WebSocket 库。   GitHub支持代理设置
支持分片儿处理请求返回内容
支持WebSocket
 
5. zt-zip:  压缩和解压库。  GitHub压缩和解压
单独操作文件压缩和解压。
替换zip文件中的某个文件
 
6. aFileChooser :文件选择器,用于选择需要操作的文件  GitHub 
7. image-chooser-library : 图片和视频的选择库。  GitHub   Demo 
8. jsoup:  HTML解析,并且能很好理解DOM,CSS,以及JQuery。 GitHub   官方    PS:这是java库。做网页爬虫(Crawler,Robot)必备。 
9. toml: 这是个跨语言的配置信息存取方案。 GitHub 
10. Androiton-Action-Bar-Icons: 一个针对Android 优化过的ICON图标集。  GitHub   Demo 
11. 推荐一个Android整体框架:ThinkAndroid 集成了ioc,orm,下载,缓存等模块,能让开发更加快速和高效,同时还是国人项目。 GitHub 
12. 如果你想要更快的网络传输和加载速度可以试试OKHTTP,他实现了Google开发的SPDY协议,通过复用一个Socket,缩短网络加载时间。 关于SPDY看这里    OKHTTP 
13. Android-ProgressFragment :等待数据的时候,支持显示等待符号的Fragment控件。 GitHub 
14. 关于播放视频,不要再去研究什么FFMPEG了,too slow,国人有个非常非常出色的开源项目叫Vitamio,让你播放视频简单如abc。 GitHub   官方网站 
15. AndroidCommon :Android常用的一些库和功能,如缓存,下拉列表,下载管理,静默安装等。感谢 Trinea  GitHub 
16. ion: 让Android的网络操作变得极其简单,支持异步获取和处理JSON,支持Android文件下载(同时支持下载进度条绑定),支持安全链接和代理。超级推荐!  GitHub 

2:开源框架或者第三方库

举例:

1: Android下拉刷新组件:Android-PullToRefresh

2:在一个ListView中通过拖拽对已有的数据进行排序操作:Drag-Sort-Listview

3:SlidingMenu 能非常容易的让开发者实现程序的抽屉效果

4. 使用上拉更多,下拉刷新:https://github.com/JosephPeng/XListView-Android 
这个是github上面更为火爆的:https://github.com/chrisbanes/Android-PullToRefresh

5. 侧滑的菜单: SlidingMenu.rar (自己导入support-4v包)推荐github上面一个很好的库,不过这个库有少少错误,修改过来就好了,附上github地址与修改地址。 
github: https://github.com/jfeinstein10/SlidingMenu 
修改地址:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=262755&reltid=249556&pre_thread_id=0&pre_pos=5&ext=CB 
其实修改的问题就是: 修改SlidingMenu library中的 SlidingFragmentActivity,让它继承于SherlockFragmentActivity,重新编译library导入

6. 水平移动导航条关联ViewPage:
http://www.eoeandroid.com/thread-175041-1-1.html

7 这个是ViewPage带动画的,比较优秀: https://github.com/jfeinstein10/JazzyViewPager
8. 数据库处理使用ormlite:http://ormlite.com/(文档全,注解的形式因此较慢) or      greenDroid:https://github.com/greenrobot/greenDAO(据评测最快,不过每次需要java编译较为麻烦)   or    ActiveAndroid:https://github.com/pardom/ActiveAndroid(没有使用过)    or    https://github.com/satyan/sugar(轻量简单, 下次项目使用)

9. get,post的请求使用:https://github.com/loopj/android-async-http  或者  使用nio的库:https://github.com/koush/ion 
https://github.com/koush/AndroidAsync  库支持程序退出后继续下载

10. 图片加载,包括ListView显示图片加载使用:https://github.com/square/picasso ,推荐这个,代码中考虑的更为的周全
https://github.com/thest1/LazyList  这个是我在项目中使用的

7. Json数据解析,有很多种,推荐使用FastJason:http://code.alibabatech.com/wiki/display/FastJSON/Home
8. ListView带快速搜索与键入搜索: listview右则搜索.rar

9. 推荐一个AFinal框架,不错,集合了FinalDB、FinalActivity、FinalHttp、FinalBitmap四个功能与一身,不过在单一使用的情况下,还是使用单一功能的框架比较好

10. 仿IPhone时间滚轮控件: iPhone时间转轮控件.rar


11. 在android sdk3.0以下使用ActionBar  安装使用教程(亲测)http://blog.csdn.net/daguaio_o/article/details/8028695

12. 多线程多任务队列断点下载,同时也提供开始、暂停功能,更多功能有待发掘,开源。本身jar有500k,感觉有点儿大,建议根据自己需要提取所需的代码。https://github.com/white-cat/ThinkAndroid


13. GreenDroid 一个漂亮的android ui库,推荐使用QuickAction


14. 手势放大缩小,双击放大缩小图片:https://github.com/jasonpolites/gesture-imageview


15. android缓存框架:https://github.com/yangfuhai/ASimpleCache


16. 把优酷、土豆等取出它们真是的视频播放地址:http://vparser.com/


17. 开源中国的Maven库:http://maven.oschina.net/static/help.html


18. 针对新浪微博,腾讯微博的认证与分享demo:https://github.com/cstdr/WeiboSDKDemo.git


19. 一个可以替换ImageView的工具,smartImageView,来自github:http://loopj.com/android-smart-image-view/


20. 图片放大与缩小:github的phoneView  如果需要在放大缩小上再加上旋转,请参考集合项目https://github.com/codepanda-ch/android-gestureimageview


21. 强大的时间处理:joda     http://sourceforge.net/projects/joda-time/files/joda-time/2.3/

22. 功能众多的工具包:apcahe lang       http://commons.apache.org/proper/commons-lang/download_lang.cgi

23. 收集了很多的github上面的开源库列表: https://github.com/Trinea/android-open-project

24、volley

项目地址 https://github.com/smanikandan14/Volley-demo
JSON,图像等的异步下载;
网络请求的排序(scheduling)
网络请求的优先级处理
缓存
多级别取消请求
和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)
25、android-async-http
项目地址:https://github.com/loopj/android-async-http,文档介绍:http://loopj.com/android-async-http/
在匿名回调中处理请求结果
在UI线程外进行http请求
文件断点上传
智能重试
默认gzip压缩
支持解析成Json格式
可将Cookies持久化到SharedPreferences
26、Afinal框架
项目地址:https://github.com/yangfuhai/afinal
主要有四大模块:
数据库模块:Android中的orm框架,使用了线程池对sqlite进行操作。
注解模块:Android中的ioc框架,完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。
网络模块:通过httpclient进行封装http数据请求,支持Ajax方式加载,支持下载、上传文件功能。
图片缓存模块:通过FinalBitmap,imageview加载bitmap的时候无需考虑bitmap加载过程中出现的oom和Android容器快速滑动时候出现的图片错位等现象。
FinalBitmap可以配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。FinalBitmap的内存管理使用lru算法,没有使用弱引用(Android2.3以后Google已经不建议使用弱引用,Android2.3后强行回收软引用和弱引用,详情查看Android官方文档),更好的管理bitmap内存。FinalBitmap可以自定义下载器,用来扩展其他协议显示网络图片,比如ftp等。同时可以自定义bitmap显示器,
在imageview显示图片的时候播放动画等(默认是渐变动画显示)。
27、xUtils框架
项目地址:https://github.com/wyouflf/xUtils,主要有四大模块:
数据库模块:
Android 中的 orm 框架,一行代码就可以进行增删改查;
支持事务,默认关闭;
可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);
支持绑定外键,保存实体时外键关联实体自动保存或更新;
自动加载外键关联实体,支持延时加载;
支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。
注解模块:
Android中的 ioc 框架,完全注解方式就可以进行 UI,资源和事件绑定;
新的事件绑定方式,使用混淆工具混淆后仍可正常工作;
目前支持常用的20种事件绑定,参见 View Common Event Listener 类和包com.lidroid.xutils.view.annotation.event。
网络模块:
支持同步,异步方式的请求;
支持大文件上传,上传大文件不会oom;
支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;
下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;
返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。
图片缓存模块:
加载bitmap的时候无需考虑bitmap加载过程中出现的oom和Android容器快速滑动时候出现的图片错位等现象;
支持加载网络图片和本地图片;
内存管理使用lru算法,更好的管理bitmap内存;
可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。
28、ThinkAndroid
项目地址:https://github.com/white-cat/ThinkAndroid
主要有以下模块:
MVC模块:实现视图与模型的分离。
ioc模块:Android中的ioc模块,完全注解方式就可以进行UI绑定、res中的资源的读取、以及对象的初始化。 
数据库模块:Android中的orm框架,使用了线程池对sqlite进行操作。 
http模块:通过httpclient进行封装http数据请求,支持异步及同步方式加载。
缓存模块:通过简单的配置及设计可以很好的实现缓存,对缓存可以随意的配置
图片缓存模块:imageview加载图片的时候无需考虑图片加载过程中出现的oom和Android容器快速滑动时候出现的图片错位等现象。
配置器模块:可以对简易的实现配对配置的操作,目前配置文件可以支持Preference、Properties对配置进行存取。
日志打印模块:可以较快的轻易的是实现日志打印,支持日志打印的扩展,目前支持对sdcard写入本地打印、以及控制台打印
下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。
网络状态检测模块:当网络状态改变时,对其进行检。
29、LoonAndroid
项目地址:https://github.com/gdpancheng/LoonAndroid
主要有以下模块:
自动注入框架(只需要继承框架内的APP既可)
图片加载框架(多重缓存,自动回收,最大限度保证内存的安全性)
网络请求模块(继承了基本上现在所有的http请求)
eventbus(集成一个开源的框架)
验证框架(集成开源框架)
Json解析(支持解析成集合或者对象)
数据库(不知道是哪位写的 忘记了)
多线程断点下载(自动判断是否支持多线程,判断是否是重定向)
自动更新模块
一系列工具类
其中的 Volley 在2013 年有研究过,扩展性非常好,个人比较喜欢的风格。其他如 Android-async-http、Afinal 也相当不错。

其他:
1:Android-Flip  : 轻松实现类似FlipBoard的翻页功能
2:picasso:   加载网络图片
3:cropper:Android截图和旋转库,轻松实现头像和一些场景下的图片操作
4:StickyGridHeaders:给GridView加上Header
5:Background-ViewPage:支持背景图同时滑动的ViewPager

30:Android开源框架Universal-Image-Loader

具体使用与配置详见:
http://blog.csdn.net/xiaanming/article/details/26810303
这个开源库特征:
1、多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等;
2、支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置;
3、支持图片的内存缓存,文件系统缓存或者SD卡缓存;
4、支持图片下载过程的监听;
5、根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存;
6、较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片;
7、提供在较慢的网络下对图片进行加载。

我们一般去加载大量的图片的时候,都会做缓存策略,缓存又分为内存缓存和硬盘缓存,异步加载大量图片,使用的内存缓存是LruCache这个类,LRU是Least Recently Used 近期最少使用算法,我们可以给LruCache设定一个缓存图片的最大值,它会自动帮我们管理好缓存的图片总大小是否超过我们设定的值, 超过就删除近期最少使用的图片,而作为一个强大的图片加载框架,Universal-Image-Loader自然也提供了多种图片的缓存策略,下面就来详细的介绍下。


内存缓存
首先我们来了解下什么是强引用和什么是弱引用?

强引用是指创建一个对象并把这个对象赋给一个引用变量,强引用有引用变量指向时永远不会被垃圾回收。即使内存不足的时候宁愿报OOM也不被垃圾回收器回收,我们new的对象都是强引用。

弱引用通过weakReference类来实现,它具有很强的不确定性,如果垃圾回收器扫描到有着WeakReference的对象,就会将其回收释放内存。

现在我们来看Universal-Image-Loader有哪些内存缓存策略

1. 只使用的是强引用缓存 

·LruMemoryCache(这个类就是这个开源框架默认的内存缓存类,缓存的是bitmap的强引用,下面我会从源码上面分析这个类)

2.使用强引用和弱引用相结合的缓存
·UsingFreqLimitedMemoryCache(如果缓存的图片总量超过限定值,先删除使用频率最小的bitmap)
·LRULimitedMemoryCache(这个也是使用的lru算法,和LruMemoryCache不同的是,他缓存的是bitmap的弱引用
·FIFOLimitedMemoryCache(先进先出的缓存策略,当超过设定值,先删除最先加入缓存的bitmap)
·LargestLimitedMemoryCache(当超过缓存限定值,先删除最大的bitmap对象)
·LimitedAgeMemoryCache(当 bitmap加入缓存中的时间超过我们设定的值,将其删除)
3.只使用弱引用缓存
·WeakMemoryCache(这个类缓存bitmap的总大小没有限制,唯一不足的地方就是不稳定,缓存的图片容易被回收掉)
上面介绍了Universal-Image-Loader所提供的所有的内存缓存的类,当然我们也可以使用我们自己写的内存缓存类,我们还要看看要怎么将这些内存缓存加入到我们的项目中,我们只需要配置ImageLoaderConfiguration.memoryCache(...),如下:
ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)  
        .memoryCache(new WeakMemoryCache())  
        .build();
下面我们来分析LruMemoryCache这个类的源代码
package com.nostra13.universalimageloader.cache.memory.impl;  
   
import android.graphics.Bitmap;  
import com.nostra13.universalimageloader.cache.memory.MemoryCacheAware;  
   
import java.util.Collection;  
import java.util.HashSet;  
import java.util.LinkedHashMap;  
import java.util.Map;  

public class LruMemoryCache implements MemoryCacheAware<String, Bitmap> {  
   
    private final LinkedHashMap<String, Bitmap> map;  
   
    private final int maxSize;  
    /** Size of this cache in bytes */  
    private int size;  
   
    /** @param maxSize Maximum sum of the sizes of the Bitmaps in this cache */  
    public LruMemoryCache(int maxSize) {  
        if (maxSize <= 0) {  
            throw new IllegalArgumentException("maxSize <= 0");  
        }  
        this.maxSize = maxSize;  
        this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);  
    }  
   
    /** 
     * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head 
     * of the queue. This returns null if a Bitmap is not cached. 
     */  
    @Override  
    public final Bitmap get(String key) {  
        if (key == null) {  
            throw new NullPointerException("key == null");  
        }  
   
        synchronized (this) {  
            return map.get(key);  
        }  
    }  
   
    /** Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue. */  
    @Override  
    public final boolean put(String key, Bitmap value) {  
        if (key == null || value == null) {  
            throw new NullPointerException("key == null || value == null");  
        }  
   
        synchronized (this) {  
            size += sizeOf(key, value);  
            Bitmap previous = map.put(key, value);  
            if (previous != null) {  
                size -= sizeOf(key, previous);  
            }  
        }  
   
        trimToSize(maxSize);  
        return true;  
    }  
   
    /** 
     * Remove the eldest entries until the total of remaining entries is at or below the requested size. 
     * 
     * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements. 
     */  
    private void trimToSize(int maxSize) {  
        while (true) {  
            String key;  
            Bitmap value;  
            synchronized (this) {  
                if (size < 0 || (map.isEmpty() && size != 0)) {  
                    throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!");  
                }  
   
                if (size <= maxSize || map.isEmpty()) {  
                    break;  
                }  
   
                Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator().next();  
                if (toEvict == null) {  
                    break;  
                }  
                key = toEvict.getKey();  
                value = toEvict.getValue();  
                map.remove(key);  
                size -= sizeOf(key, value);  
            }  
        }  
    }  
   
    /** Removes the entry for {@code key} if it exists. */  
    @Override  
    public final void remove(String key) {  
        if (key == null) {  
            throw new NullPointerException("key == null");  
        }  
   
        synchronized (this) {  
            Bitmap previous = map.remove(key);  
            if (previous != null) {  
                size -= sizeOf(key, previous);  
            }  
        }  
    }  
   
    @Override  
    public Collection<String> keys() {  
        synchronized (this) {  
            return new HashSet<String>(map.keySet());  
        }  
    }  
   
    @Override  
    public void clear() {  
        trimToSize(-1); // -1 will evict 0-sized elements  
    }  
   
    /** 
     * Returns the size {@code Bitmap} in bytes. 
     * <p/> 
     * An entry's size must not change while it is in the cache. 
     */  
    private int sizeOf(String key, Bitmap value) {  
        return value.getRowBytes() * value.getHeight();  
    }  
   
    @Override  
    public synchronized final String toString() {  
        return String.format("LruCache[maxSize=%d]", maxSize);  
    }  
}

我们可以看到这个类中维护的是一个LinkedHashMap,在LruMemoryCache构造函数中我们可以看到,我们为其设置了一个缓存图片的最大值maxSize,并实例化LinkedHashMap,而从LinkedHashMap构造函数的第三个参数为ture,表示它是按照访问顺序进行排序的。


我们来看将bitmap加入到LruMemoryCache的方法put(String key, Bitmap value), 第61行,sizeOf()是计算每张图片所占的byte数,size是记录当前缓存bitmap的总大小,如果该key之前就缓存了bitmap,我们需要将之前的bitmap减掉去,接下来看trimToSize()方法,我们直接看86行,如果当前缓存的bitmap总数小于设定值maxSize,不做任何处理,如果当前缓存的bitmap总数大于maxSize,删除LinkedHashMap中的第一个元素,size中减去该bitmap对应的byte数。


我们可以看到该缓存类比较简单,逻辑也比较清晰,如果大家想知道其他内存缓存的逻辑,可以去分析分析其源码,在这里我简单说下FIFOLimitedMemoryCache的实现逻辑,该类使用的HashMap来缓存bitmap的弱引用,然后使用LinkedList来保存成功加入到FIFOLimitedMemoryCache的bitmap的强引用,如果加入的FIFOLimitedMemoryCache的bitmap总数超过限定值,直接删除LinkedList的第一个元素,所以就实现了先进先出的缓存策略,其他的缓存都类似,有兴趣的可以去看看。


硬盘缓存

接下来就给大家分析分析硬盘缓存的策略,这个框架也提供了几种常见的缓存策略,当然如果你觉得都不符合你的要求,你也可以自己去扩展。

·FileCountLimitedDiscCache(可以设定缓存图片的个数,当超过设定值,删除掉最先加入到硬盘的文件)
·LimitedAgeDiscCache(设定文件存活的最长时间,当超过这个值,就删除该文件)
·TotalSizeLimitedDiscCache(设定缓存bitmap的最大值,当超过这个值,删除最先加入到硬盘的文件)
·UnlimitedDiscCache(这个缓存类没有任何的限制)

下面我们就来分析分析TotalSizeLimitedDiscCache的源码实现
package com.nostra13.universalimageloader.cache.disc.impl;  
   
import com.nostra13.universalimageloader.cache.disc.LimitedDiscCache;  
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;  
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;  
import com.nostra13.universalimageloader.utils.L;  
   
import java.io.File;  
   
/** 
 * Disc cache limited by total cache size. If cache size exceeds specified limit then file with the most oldest last 
 * usage date will be deleted. 
 * 
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 
 * @see LimitedDiscCache 
 * @since 1.0.0 
 */  
public class TotalSizeLimitedDiscCache extends LimitedDiscCache {  
   
    private static final int MIN_NORMAL_CACHE_SIZE_IN_MB = 2;  
    private static final int MIN_NORMAL_CACHE_SIZE = MIN_NORMAL_CACHE_SIZE_IN_MB * 1024 * 1024;  
   
    /** 
     * @param cacheDir     Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                     needed for right cache limit work. 
     * @param maxCacheSize Maximum cache directory size (in bytes). If cache size exceeds this limit then file with the 
     *                     most oldest last usage date will be deleted. 
     */  
    public TotalSizeLimitedDiscCache(File cacheDir, int maxCacheSize) {  
        this(cacheDir, DefaultConfigurationFactory.createFileNameGenerator(), maxCacheSize);  
    }  
   
    /** 
     * @param cacheDir          Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                          needed for right cache limit work. 
     * @param fileNameGenerator Name generator for cached files 
     * @param maxCacheSize      Maximum cache directory size (in bytes). If cache size exceeds this limit then file with the 
     *                          most oldest last usage date will be deleted. 
     */  
    public TotalSizeLimitedDiscCache(File cacheDir, FileNameGenerator fileNameGenerator, int maxCacheSize) {  
        super(cacheDir, fileNameGenerator, maxCacheSize);  
        if (maxCacheSize < MIN_NORMAL_CACHE_SIZE) {  
            L.w("You set too small disc cache size (less than %1$d Mb)", MIN_NORMAL_CACHE_SIZE_IN_MB);  
        }  
    }  
   
    @Override  
    protected int getSize(File file) {  
        return (int) file.length();  
    }  
}

这个类是继承LimitedDiscCache,除了两个构造函数之外,还重写了getSize()方法,返回文件的大小,接下来我们就来看看LimitedDiscCache。

package com.nostra13.universalimageloader.cache.disc;  
   
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;  
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;  
   
import java.io.File;  
import java.util.Collections;  
import java.util.HashMap;  
import java.util.Map;  
import java.util.Map.Entry;  
import java.util.Set;  
import java.util.concurrent.atomic.AtomicInteger;  
   
/** 
 * Abstract disc cache limited by some parameter. If cache exceeds specified limit then file with the most oldest last 
 * usage date will be deleted. 
 * 
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 
 * @see BaseDiscCache 
 * @see FileNameGenerator 
 * @since 1.0.0 
 */  
public abstract class LimitedDiscCache extends BaseDiscCache {  
   
    private static final int INVALID_SIZE = -1;  
   
    //记录缓存文件的大小  
    private final AtomicInteger cacheSize;  
    //缓存文件的最大值  
    private final int sizeLimit;  
    private final Map<File, Long> lastUsageDates = Collections.synchronizedMap(new HashMap<File, Long>());  
   
    /** 
     * @param cacheDir  Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                  needed for right cache limit work. 
     * @param sizeLimit Cache limit value. If cache exceeds this limit then file with the most oldest last usage date 
     *                  will be deleted. 
     */  
    public LimitedDiscCache(File cacheDir, int sizeLimit) {  
        this(cacheDir, DefaultConfigurationFactory.createFileNameGenerator(), sizeLimit);  
    }  
   
    /** 
     * @param cacheDir          Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
     *                          needed for right cache limit work. 
     * @param fileNameGenerator Name generator for cached files 
     * @param sizeLimit         Cache limit value. If cache exceeds this limit then file with the most oldest last usage date 
     *                          will be deleted. 
     */  
    public LimitedDiscCache(File cacheDir, FileNameGenerator fileNameGenerator, int sizeLimit) {  
        super(cacheDir, fileNameGenerator);  
        this.sizeLimit = sizeLimit;  
        cacheSize = new AtomicInteger();  
        calculateCacheSizeAndFillUsageMap();  
    }  
   
    /** 
     * 另开线程计算cacheDir里面文件的大小,并将文件和最后修改的毫秒数加入到Map中 
     */  
    private void calculateCacheSizeAndFillUsageMap() {  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                int size = 0;  
                File[] cachedFiles = cacheDir.listFiles();  
                if (cachedFiles != null) { // rarely but it can happen, don't know why  
                    for (File cachedFile : cachedFiles) {  
                        //getSize()是一个抽象方法,子类自行实现getSize()的逻辑  
                        size += getSize(cachedFile);  
                        //将文件的最后修改时间加入到map中  
                        lastUsageDates.put(cachedFile, cachedFile.lastModified());  
                    }  
                    cacheSize.set(size);  
                }  
            }  
        }).start();  
    }  
   
    /** 
     * 将文件添加到Map中,并计算缓存文件的大小是否超过了我们设置的最大缓存数 
     * 超过了就删除最先加入的那个文件 
     */  
    @Override  
    public void put(String key, File file) {  
        //要加入文件的大小  
        int valueSize = getSize(file);  
           
        //获取当前缓存文件大小总数  
        int curCacheSize = cacheSize.get();  
        //判断是否超过设定的最大缓存值  
        while (curCacheSize + valueSize > sizeLimit) {  
            int freedSize = removeNext();  
            if (freedSize == INVALID_SIZE) break; // cache is empty (have nothing to delete)  
            curCacheSize = cacheSize.addAndGet(-freedSize);  
        }  
        cacheSize.addAndGet(valueSize);  
   
        Long currentTime = System.currentTimeMillis();  
        file.setLastModified(currentTime);  
        lastUsageDates.put(file, currentTime);  
    }  
   
    /** 
     * 根据key生成文件 
     */  
    @Override  
    public File get(String key) {  
        File file = super.get(key);  
   
        Long currentTime = System.currentTimeMillis();  
        file.setLastModified(currentTime);  
        lastUsageDates.put(file, currentTime);  
   
        return file;  
    }  
   
    /** 
     * 硬盘缓存的清理 
     */  
    @Override  
    public void clear() {  
        lastUsageDates.clear();  
        cacheSize.set(0);  
        super.clear();  
    }  
   
       
    /** 
     * 获取最早加入的缓存文件,并将其删除 
     */  
    private int removeNext() {  
        if (lastUsageDates.isEmpty()) {  
            return INVALID_SIZE;  
        }  
        Long oldestUsage = null;  
        File mostLongUsedFile = null;  
           
        Set<Entry<File, Long>> entries = lastUsageDates.entrySet();  
        synchronized (lastUsageDates) {  
            for (Entry<File, Long> entry : entries) {  
                if (mostLongUsedFile == null) {  
                    mostLongUsedFile = entry.getKey();  
                    oldestUsage = entry.getValue();  
                } else {  
                    Long lastValueUsage = entry.getValue();  
                    if (lastValueUsage < oldestUsage) {  
                        oldestUsage = lastValueUsage;  
                        mostLongUsedFile = entry.getKey();  
                    }  
                }  
            }  
        }  
   
        int fileSize = 0;  
        if (mostLongUsedFile != null) {  
            if (mostLongUsedFile.exists()) {  
                fileSize = getSize(mostLongUsedFile);  
                if (mostLongUsedFile.delete()) {  
                    lastUsageDates.remove(mostLongUsedFile);  
                }  
            } else {  
                lastUsageDates.remove(mostLongUsedFile);  
            }  
        }  
        return fileSize;  
    }  
   
    /** 
     * 抽象方法,获取文件大小 
     * @param file 
     * @return 
     */  
    protected abstract int getSize(File file);  
}

在构造方法中,第69行有一个方法calculateCacheSizeAndFillUsageMap(),该方法是计算cacheDir的文件大小,并将文件和文件的最后修改时间加入到Map中。
然后是将文件加入硬盘缓存的方法put(),在106行判断当前文件的缓存总数加上即将要加入缓存的文件大小是否超过缓存设定值,如果超过了执行removeNext()方法,接下来就来看看这个方法的具体实现,150-167中找出最先加入硬盘的文件,169-180中将其从文件硬盘中删除,并返回该文件的大小,删除成功之后成员变量cacheSize需要减掉改文件大小。
FileCountLimitedDiscCache这个类实现逻辑跟TotalSizeLimitedDiscCache是一样的,区别在于getSize()方法,前者返回1,表示为文件数是1,后者返回文件的大小。
等我写完了这篇文章,我才发现FileCountLimitedDiscCache和TotalSizeLimitedDiscCache在最新的源码中已经删除了,加入了LruDiscCache,由于我的是之前的源码,所以我也不改了,大家如果想要了解LruDiscCache可以去看最新的源码,我这里就不介绍了,还好内存缓存的没变化,下面分析的是最新的源码中的部分,我们在使用中可以不自行配置硬盘缓存策略,直接用DefaultConfigurationFactory中的就行了

我们看DefaultConfigurationFactory这个类的createDiskCache()方法
/** 
 * Creates default implementation of {@link DiskCache} depends on incoming parameters 
 */  
public static DiskCache createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator,  
        long diskCacheSize, int diskCacheFileCount) {  
    File reserveCacheDir = createReserveDiskCacheDir(context);  
    if (diskCacheSize > 0 || diskCacheFileCount > 0) {  
        File individualCacheDir = StorageUtils.getIndividualCacheDirectory(context);  
        LruDiscCache diskCache = new LruDiscCache(individualCacheDir, diskCacheFileNameGenerator, diskCacheSize,  
                diskCacheFileCount);  
        diskCache.setReserveCacheDir(reserveCacheDir);  
        return diskCache;  
    } else {  
        File cacheDir = StorageUtils.getCacheDirectory(context);  
        return new UnlimitedDiscCache(cacheDir, reserveCacheDir, diskCacheFileNameGenerator);  
    }  
}
如果我们在ImageLoaderConfiguration中配置了diskCacheSize和diskCacheFileCount,它使用的就是LruDiscCache,否则使用的是UnlimitedDiscCache,在最新的源码中还有一个硬盘缓存类可以配置,那就是LimitedAgeDiscCache,可以在ImageLoaderConfiguration.diskCache(...)配置。




0 0
原创粉丝点击