您的位置:首页 > 移动开发 > Android开发

开源项目学习:Android-Universal-Image-Loader-Part2

2015-03-13 16:38 417 查看
这次就是专门学习内存储存了。

从内部储存这块要学习的内容有

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;
}
});
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: