//加入新创建的对象之后需要重新计算size大小
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
//每次新加入对象都需要调用trimToSize方法看是否需要回收
trimToSize(maxSize);
return createdValue;
}
}
/**
- Caches {@code value} for {@code key}. The value is moved to the head of
- the queue.
- @return the previous value mapped by {@code key}.
*/
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException(“key == null || value == null”);
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value); //size加上预put对象的大小
previous = map.put(key, value);
if (previous != null) {
//如果之前存在键为key的对象,则size应该减去原来对象的大小
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
//每次新加入对象都需要调用trimToSize方法看是否需要回收
trimToSize(maxSize);
return previous;
}
/**
- @param maxSize the maximum size of the cache before returning. May be -1
-
to evict even 0-sized elements.
- 此方法根据maxSize来调整内存cache的大小,如果maxSize传入-1,则清空缓存中的所有对象
*/
private void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
- “.sizeOf() is reporting inconsistent results!”);
}
//如果当前size小于maxSize或者map没有任何对象,则结束循环
if (size <= maxSize || map.isEmpty()) {
break;
}
//移除链表头部的元素,并进入下一次循环
Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++; //回收次数+1
}
entryRemoved(true, key, value, null);
}
}
/**
- Removes the entry for {@code key} if it exists.
- @return the previous value mapped by {@code key}.
- 从内存缓存中根据key值移除某个对象并返回该对象
*/
public final V remove(K key) {
if (key == null) {
throw new NullPointerException(“key == null”);
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;
}
/**
- Called for entries that have been evicted or removed. This method is
- invoked when a value is evicted to make space, removed by a call to
- {@link #remove}, or replaced by a call to {@link #put}. The default
- implementation does nothing.
-
The method is called without synchronization: other threads may
- access the cache while this method is executing.
- @param evicted true if the entry is being removed to make space, false
-
if the removal was caused by a {@link #put} or {@link #remove}.
- @param newValue the new value for {@code key}, if it exists. If non-null,
-
this removal was caused by a {@link #put}. Otherwise it was caused by
-
an eviction or a {@link #remove}.
*/
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
/**
- Called after a cache miss to compute a value for the corresponding key.
- Returns the computed value or null if no value can be computed. The
- default implementation returns null.
-
The method is called without synchronization: other threads may
- access the cache while this method is executing.
-
If a value for {@code key} exists in the cache when this method
- returns, the created value will be released with {@link #entryRemoved}
- and discarded. This can occur when multiple threads request the same key
- at the same time (causing multiple values to be created), or when one
- thread calls {@link #put} while another is creating a value for the same
- key.
*/
protected V create(K key) {
return null;
}
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + “=” + value);
}
return result;
}
/**
- Returns the size of the entry for {@code key} and {@code value} in
- user-defined units. The default implementation returns 1 so that size
- is the number of entries and max size is the maximum number of entries.
-
An entry's size must not change while it is in the cache.
- 用来计算单个对象的大小,这里默认返回1,一般需要重写该方法来计算对象的大小
- xUtils中创建LruMemoryCache时就重写了sizeOf方法来计算bitmap的大小
- mMemoryCache = new LruMemoryCache<MemoryCacheKey, Bitmap>(globalConfig.getMemoryCacheSize()) {
-
@Override
-
protected int sizeOf(MemoryCacheKey key, Bitmap bitmap) {
-
if (bitmap == null) return 0;
-
return bitmap.getRowBytes() * bitmap.getHeight();
-
}
- };
*/
protected int sizeOf(K key, V value) {
return 1;
}
/**
- Clear the cache, calling {@link #entryRemoved} on each removed entry.
- 清空内存缓存
*/
public final void evictAll() {
trimToSize(-1); // -1 will evict 0-sized elements
}
/**
- For caches that do not override {@link #sizeOf}, this returns the number
- of entries in the cache. For all other caches, this returns the sum of
- the sizes of the entries in this cache.
*/
public synchronized final int size() {
return size;
}
/**
- For caches that do not override {@link #sizeOf}, this returns the maximum
- number of entries in the cache. For all other caches, this returns the
- maximum sum of the sizes of the entries in this cache.
*/
public synchronized final int maxSize() {
return maxSize;
}
/**
- Returns the number of times {@link #get} returned a value.
*/
public synchronized final int hitCount() {
return hitCount;
}
/**
- Returns the number of times {@link #get} returned null or required a new
- value to be created.
*/
public synchronized final int missCount() {
return missCount;
}
/**
- Returns the number of times {@link #create(Object)} returned a value.
*/
public synchronized final int createCount() {
return createCount;
}
/**
- Returns the number of times {@link #put} was called.
*/
public synchronized final int putCount() {
return putCount;
}
/**
- Returns the number of values that have been evicted.
*/
public synchronized final int evictionCount() {
return evictionCount;
}
/**
- Returns a copy of the current contents of the cache, ordered from least
- recently accessed to most recently accessed.
*/
public synchronized final Map<K, V> snapshot() {
return new LinkedHashMap<K, V>(map);
}
@Override public synchronized final String toString() {
int accesses = hitCount + missCount;
int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
return String.format(“LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]”,
maxSize, hitCount, missCount, hitPercent);
}
}
看完代码是不是觉得内存缓存的实现其实很简单?
由于文章篇幅问题复制链接查看详细文章以及获取学习笔记链接:https://shimo.im/docs/QVGDhCjVKvQ6r6TJ
或者可以查看我的【Github】里可以查看
Android看起来知识点就那么多,但是如果你把它全部细化出来,你会看到一张这样的图片(部分):
是不是很吓人,但是如果我们按模块每天学习一点,几个月你是可以拿下的!学完上面70%的知识60w年薪可以做到!(思维脑图可以在我的【Github】里可以查看)我把上面的学习思维导图分为4个部分:
1.Java语言进阶与Android相关技术核
Android应用是由Java语言进行开发的,SDK也是由Java语言编写,对于Android来说,只要SDK没有用Kotlin重写,那么Java语言是都需要学习的。而且Android APK的后台服务器程序大概率是Java语言构建,所以掌握Java也是一种必然,这就是为什么BAT面试为什么死抠你的Java水平。
2.APP开发框架体系
APP开发这块知识是现今使用者最多的,并且大多都是CV工程师,程序员界的2-8定律:80%的问题只需要使用20%的知识就可以解决,Android开发也不例外。因而,我们大部分人已经逐步变成了代码搬运工而自己却不知道。代码容易搬运,架构体系却难以复制,要成为架构师,你必须自己亲自去项目实战,读源码,研究原理。
3.性能调优
我们不仅仅对项目要运筹帷幄,还要能解决一切性能问题。只有具备深厚的代码功底,深入学习源码原理以及使用工具进行测试和检查调优,才能达到知其然,知其所以然的效果。
4.移动架构师专题项目实战
架构师不是天生的,是在项目中磨练起来的,所以,我们学了技术就需要结合项目进行实战训练,那么在Android里面最常用的架构无外乎 MVC,MVP,MVVM,但是这些思想如果和模块化,层次化,组件化混和在一起,那就不是一件那么简单的事了,我们需要一个真正身经百战的架构师才能讲解透彻其中蕴含的深理。
最后
分享读者
作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。
被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!
我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。
主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
有3-5年以上经验的小伙伴深入学习提升。
主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。
[外链图片转存中…(img-rDbcuKB4-1715251410904)]
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!