开源项目学习:Android-Universal-Image-Loader-Part2
2015-03-13 16:38
417 查看
这次就是专门学习内存储存了。
从内部储存这块要学习的内容有
1. 简单了解类的继承关系
2. 关注里面的一些熟悉的语法但是陌生的用法 --嵌入到了代码部分用红色标注了
3. 关注函数的命名规律;
4. 关注里面出现的比较常用的算法
5、 接口作为参数
1.继承关系
首先,最重要的就是要了解为什么MemoryCache 要有这些方法呢?
我们从缓存里面存、取数据那么就要有一个key对应去索引;
接下来,知道了key,那么怎么去得到缓存数据、放数据到缓存呢?
在BaseMemoryCache里面就有这么一个:
/** Stores not strong references to objects */
private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
Collections是集合的接口,里面提供了一个synchronizedMap的方法;这个方法的特点是函数返回的线程安全的HashMap,所以保证多线程访问数据的一致性;
比如我们如果要存数据
对应的createReference是一个抽象方法,在FIFOLimitMemoryCache中的具体实现就是一个弱引用。
注意--毕竟不是所有的子类都是需要这个弱引用,所以不在基类里面去实现而是放到子类去实现比较适合
@Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
如果要取出缓存图片
这里就涉及到了内存的储存方式,引用下人家的话:
【
回顾:
(1)StrongReference(强引用)
强引用就是平时经常使用的,如常规new Object()。如果一个对象具有强引用,那垃圾回收器绝不会回收。内存不足,甚至出现OOM时,也不会随意回收强引用的对象。
(2)SoftReference(软引用)
在内存空间足够,垃圾回收器不会回收它;如果内存空间不足,垃圾回收器就会回收软引用的对象。
(3)WeakReference(弱引用)
弱引用相对软引用,具有更短暂的生命周期。常规的GC,只要被扫描到,都会直接被回收。
(4)PhantomReference(虚引用)
虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。没用过。。。
选其一FIFOLimitedMemoryCache进行分析,构造时,必须要指定大小(单位:字节)。当设置的大小超过16MB(Android默认分配的大小好像也是这个)时,会有警告。
】
扩展下:
基本的存储关系搞清楚了,再简单了解下LimitMemoryCache,其他的类就不分析了,道理差不多;
这个类依然还是抽象类,还有一些类是要继承于它的,自然我们在使用的时候不会直接用这个类(抽象类不能实例化),但是了解它是必要的;
首先,如果我们要做一个限制大小的缓存类,那么首先我们要得到:要设置的缓存最大是多少,要缓存的内容是多大,
eg:在放入缓存的时候,肯定有个判断
另外,注意的是LimitMemoryCache虽然继承的是BaseMemoryCache,但是内存所有数据结构变了, 用的是Collections.synchronizedList(new LinkedList<Bitmap>()) ,
/**
* Contains strong references to stored objects. Each next object is added last. If hard cache size will exceed
* limit then first object is deleted (but it continue exist at {@link #softMap} and can be collected by GC at any
* time)
*/
private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());
道理和上面的synchronizedHashMap一样,Collections.synchronizedList的话参考这个:写的比较详细 http://my.oschina.net/infiniteSpace/blog/305425
所以说参考的这篇文章说BaseMemoryCache的子类都是弱引用,这个地方值得商榷~
2、命名规范问题
在类的命名上比较规范,包的命名都很好,一看就知道那个包里面是接口,哪里是实现接口的类;
有一点个人觉得不舒服就是,memory这个包里面有几个抽象类,所以我觉得要么把这几个类移到memory.impl这个包,要么在接口类的名字后面加个interface的标注;
类里面的函数的命名的规范:很符合基本的规范
静态常量名称大写
private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
每个方法都有参数标注说明
/** @param sizeLimit Maximum size for cache (in bytes) */
public LimitedMemoryCache(int sizeLimit) {
this.sizeLimit = sizeLimit;
cacheSize = new AtomicInteger();
if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB);
}
}
方法名首字母小写;
类首字母大写;
...
这些虽然都懂我,但是很多时候,在写的过程中就忘了或者懒得去标注说明;看来以后得慢慢养成刷牙般的习惯;
3、出现的算法
出现了FIFO,Fuzzy,使用频率UsingFreq,Lru算法
算法部分原理目前还很难掌握~对算法不怎么样,以后有时间再系统学下,目前能简单看得懂就行;
这个部分用一个FuzzyKeyMemoryCache简单说明下怎么利用JAVA已经做好的算法来写程序吧
4、最后,总结一下一个很迷惑我的地方:接口作为参数 --可以看到MemoryCache 和Comparator<String>是一个接口作为参数传入进来的;
在实际用的时候,接口作为参数非常有用:这样便根据传进入的参数的不同而实现不同的功能;可以把自己内部的数据暴露给外部;
比如:我们最简单的按钮监听器
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("BButton", "pressed button 1");
//change button 1's text, left icon, and type
button1.setText("hello");
button1.setLeftIcon("fa-star");
button1.setBootstrapType("success");
}
});
这个View v是怎么暴露给你的呢?
写个简单的DEMO--你可以传入参数进行不同的功能;可以获得类暴露给你的数据
从内部储存这块要学习的内容有
1. 简单了解类的继承关系
2. 关注里面的一些熟悉的语法但是陌生的用法 --嵌入到了代码部分用红色标注了
3. 关注函数的命名规律;
4. 关注里面出现的比较常用的算法
5、 接口作为参数
/******************************************************************************* package com.nostra13.universalimageloader.cache.memory; import android.graphics.Bitmap; import java.util.Collection; /** * Interface for memory cache * * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) * @since 1.9.2 */ public interface MemoryCache { /** * Puts value into cache by key * * @return <b>true</b> - if value was put into cache successfully, <b>false</b> - if value was <b>not</b> put into * cache */ boolean put(String key, Bitmap value); /** Returns value by key. If there is no value for key then null will be returned. */ Bitmap get(String key); /** Removes item by key */ Bitmap remove(String key); /** Returns all keys of cache */ Collection<String> keys(); /** Remove all items from cache */ void clear(); }
1.继承关系
首先,最重要的就是要了解为什么MemoryCache 要有这些方法呢?
我们从缓存里面存、取数据那么就要有一个key对应去索引;
接下来,知道了key,那么怎么去得到缓存数据、放数据到缓存呢?
在BaseMemoryCache里面就有这么一个:
/** Stores not strong references to objects */
private final Map<String, Reference<Bitmap>> softMap = Collections.synchronizedMap(new HashMap<String, Reference<Bitmap>>());
Collections是集合的接口,里面提供了一个synchronizedMap的方法;这个方法的特点是函数返回的线程安全的HashMap,所以保证多线程访问数据的一致性;
比如我们如果要存数据
@Override public boolean put(String key, Bitmap value) { softMap.put(key, createReference(value)); return true; }
对应的createReference是一个抽象方法,在FIFOLimitMemoryCache中的具体实现就是一个弱引用。
注意--毕竟不是所有的子类都是需要这个弱引用,所以不在基类里面去实现而是放到子类去实现比较适合
@Override
protected Reference<Bitmap> createReference(Bitmap value) {
return new WeakReference<Bitmap>(value);
}
如果要取出缓存图片
public Bitmap get(String key) { Bitmap result = null; Reference<Bitmap> reference = softMap.get(key); if (reference != null) { result = reference.get(); } return result; }
这里就涉及到了内存的储存方式,引用下人家的话:
【
回顾:
(1)StrongReference(强引用)
强引用就是平时经常使用的,如常规new Object()。如果一个对象具有强引用,那垃圾回收器绝不会回收。内存不足,甚至出现OOM时,也不会随意回收强引用的对象。
(2)SoftReference(软引用)
在内存空间足够,垃圾回收器不会回收它;如果内存空间不足,垃圾回收器就会回收软引用的对象。
(3)WeakReference(弱引用)
弱引用相对软引用,具有更短暂的生命周期。常规的GC,只要被扫描到,都会直接被回收。
(4)PhantomReference(虚引用)
虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。没用过。。。
选其一FIFOLimitedMemoryCache进行分析,构造时,必须要指定大小(单位:字节)。当设置的大小超过16MB(Android默认分配的大小好像也是这个)时,会有警告。
】
扩展下:
基本的存储关系搞清楚了,再简单了解下LimitMemoryCache,其他的类就不分析了,道理差不多;
这个类依然还是抽象类,还有一些类是要继承于它的,自然我们在使用的时候不会直接用这个类(抽象类不能实例化),但是了解它是必要的;
首先,如果我们要做一个限制大小的缓存类,那么首先我们要得到:要设置的缓存最大是多少,要缓存的内容是多大,
eg:在放入缓存的时候,肯定有个判断
@Override public boolean put(String key, Bitmap value) { boolean putSuccessfully = false; // Try to add value to hard cache int valueSize = getSize(value); //得到需要缓存的数据的大小 int sizeLimit = getSizeLimit(); //得到要设置的最大缓存是多少 int curCacheSize = cacheSize.get(); if (valueSize < sizeLimit) { while (curCacheSize + valueSize > sizeLimit) { Bitmap removedValue = removeNext(); if (hardCache.remove(removedValue)) { curCacheSize = cacheSize.addAndGet(-getSize(removedValue)); } } hardCache.add(value); cacheSize.addAndGet(valueSize); putSuccessfully = true; }
另外,注意的是LimitMemoryCache虽然继承的是BaseMemoryCache,但是内存所有数据结构变了, 用的是Collections.synchronizedList(new LinkedList<Bitmap>()) ,
/**
* Contains strong references to stored objects. Each next object is added last. If hard cache size will exceed
* limit then first object is deleted (but it continue exist at {@link #softMap} and can be collected by GC at any
* time)
*/
private final List<Bitmap> hardCache = Collections.synchronizedList(new LinkedList<Bitmap>());
道理和上面的synchronizedHashMap一样,Collections.synchronizedList的话参考这个:写的比较详细 http://my.oschina.net/infiniteSpace/blog/305425
所以说参考的这篇文章说BaseMemoryCache的子类都是弱引用,这个地方值得商榷~
2、命名规范问题
在类的命名上比较规范,包的命名都很好,一看就知道那个包里面是接口,哪里是实现接口的类;
有一点个人觉得不舒服就是,memory这个包里面有几个抽象类,所以我觉得要么把这几个类移到memory.impl这个包,要么在接口类的名字后面加个interface的标注;
类里面的函数的命名的规范:很符合基本的规范
静态常量名称大写
private static final int MAX_NORMAL_CACHE_SIZE_IN_MB = 16;
每个方法都有参数标注说明
/** @param sizeLimit Maximum size for cache (in bytes) */
public LimitedMemoryCache(int sizeLimit) {
this.sizeLimit = sizeLimit;
cacheSize = new AtomicInteger();
if (sizeLimit > MAX_NORMAL_CACHE_SIZE) {
L.w("You set too large memory cache size (more than %1$d Mb)", MAX_NORMAL_CACHE_SIZE_IN_MB);
}
}
方法名首字母小写;
类首字母大写;
...
这些虽然都懂我,但是很多时候,在写的过程中就忘了或者懒得去标注说明;看来以后得慢慢养成刷牙般的习惯;
3、出现的算法
出现了FIFO,Fuzzy,使用频率UsingFreq,Lru算法
算法部分原理目前还很难掌握~对算法不怎么样,以后有时间再系统学下,目前能简单看得懂就行;
这个部分用一个FuzzyKeyMemoryCache简单说明下怎么利用JAVA已经做好的算法来写程序吧
<span style="color:#333333;">import android.graphics.Bitmap; import com.nostra13.universalimageloader.cache.memory.MemoryCache; import java.util.Collection; import java.util.Comparator; /** * Decorator for {@link MemoryCache}. Provides special feature for cache: some different keys are considered as * equals (using {@link Comparator comparator}). And when you try to put some value into cache by key so entries with * "equals" keys will be removed from cache before.<br /> * <b>NOTE:</b> Used for internal needs. Normally you don't need to use this class. */ public class FuzzyKeyMemoryCache implements MemoryCache { private final MemoryCache cache; private final Comparator<String> keyComparator; public FuzzyKeyMemoryCache(</span><span style="color:#ff0000;">MemoryCache </span><span style="color:#333333;">cache, </span><span style="color:#ff0000;">Comparator</span><span style="color:#333333;"><String> keyComparator) { this.cache = cache; this.keyComparator = keyComparator; } @Override public boolean put(String key, Bitmap value) { // Search equal key and remove this entry synchronized (cache) { String keyToRemove = null; for (String cacheKey : cache.keys()) { //-1代表o1里的某一个属性比o2的小 0代表等于 1代表大于 if (keyComparator.compare(key, cacheKey) == 0) { keyToRemove = cacheKey; break; } } //如果判断出目前的MemoryCache里面有这个key,说明已经缓存了,所以就不用再去存了 if (keyToRemove != null) { cache.remove(keyToRemove); } } return cache.put(key, value); } @Override public Bitmap get(String key) { return cache.get(key); } @Override public Bitmap remove(String key) { return cache.remove(key); } @Override public void clear() { cache.clear(); } @Override public Collection<String> keys() { return cache.keys(); } }</span>
4、最后,总结一下一个很迷惑我的地方:接口作为参数 --可以看到MemoryCache 和Comparator<String>是一个接口作为参数传入进来的;
在实际用的时候,接口作为参数非常有用:这样便根据传进入的参数的不同而实现不同的功能;可以把自己内部的数据暴露给外部;
比如:我们最简单的按钮监听器
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("BButton", "pressed button 1");
//change button 1's text, left icon, and type
button1.setText("hello");
button1.setLeftIcon("fa-star");
button1.setBootstrapType("success");
}
});
这个View v是怎么暴露给你的呢?
写个简单的DEMO--你可以传入参数进行不同的功能;可以获得类暴露给你的数据
public interface House { <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>String window(); <span style="white-space:pre"> </span>int Bigdoor(String str); <span style="white-space:pre"> </span>void smallDoor(String str); }
public class TestHouse { void test(House house){ String windowStr=house.window(); System.out.println("从外面的窗户得到的数据"+windowStr); String str_samll="用smallDoor向外暴露数据"; house.smallDoor(str_samll); String str_big="用bigdoor向外暴露数据"; String str_int_big=house.Bigdoor(str_big)+""; System.out.println(str_int_big); } public static void main(String[] args) { TestHouse instance=new TestHouse(); instance.test(new House() { //只能进去 @Override public String window() { // TODO Auto-generated method stub return "window"; } //只能出去 @Override public void smallDoor(String str) { System.out.println(str); } //既能进去又能出来 @Override public int Bigdoor(String str) { System.out.println(str); return 2; } }); } }
相关文章推荐
- 开源项目学习:Android-Universal-Image-Loader-Part1
- 开源项目学习:Android-Universal-Image-Loader-Part3
- 开源项目Universal Image Loader for Android
- Android-Universal-Image-Loader开源项目的简要说明及使用实例
- 浅谈开源项目Android-Universal-Image-Loader(Part 3.1)
- Android-Universal-Image-Loader开源项目应用
- Android-Universal-Image-Loader开源项目的简要说明及使用实例
- [原创] 浅谈开源项目Android-Universal-Image-Loader(Part 3.1)
- 开源项目Android-Universal-Image-Loader 解析
- Android-Universal-Image-Loader(强大的图片加载、缓存的 开源项目)
- Android之开源控件Image-Android-Universal-Image-Loader的学习资料
- 开源项目Universal Image Loader for Android 说明文档 (1) 简介
- Android开源项目 --- universalimageloader项目全景UML类图高清无码版
- Android开源项目 异步图片缓存库 Universal-Image-Loader
- 开源项目:Android-Universal-Image-Loader总结
- 浅谈开源项目Android-Universal-Image-Loader
- Android-Universal-Image-Loader开源项目的简要说明及使用实例
- 开源项目Universal Image Loader for Android
- 开源项目Universal Image Loader for Android 说明文档
- 【Android】开源项目UniversalImageLoader及开源框架ImageLoader