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

这次就是专门学习内存储存了。

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

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

}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值