首页 > 编程知识 正文

delete unused android studio,apt-get 卸载

时间:2023-05-06 07:14:11 阅读:134999 作者:1057

代码,今天无意中发现Android5.0(APIlevel21 )以前的LruCache实现有错误。

因为在电脑(Java SE环境、手机以外)上测试代码很方便,所以最近在Java项目上测试了Android项目的框架代码copy,缺了一个LruCache。 我也直接复制了那个源代码,但是报告了错误。 那是下一个第一个代码的map.eldest ); 虽然是这个语句,但是因为这个方法不是Java标准API,所以被@hide了。 我也没想,就这样遍历map取出最后的要素(改为思考例程)。 LinkedHashMap的最后一个元素是其eldest ) )的,也就是LRU的),但在测试中很快发现了问题,LinkedHashMap的

但是,不凑巧的是,今天下班了,把代码copy带回到自己身边准备测试。 当我再次查询名为copy的LruCache源代码时,竟然不报告错误,在我还没明白的时候,我又回到了那一行,发现了问题。 那个代码正好和我昨天犯的错误一样,调查最后的要素作为LRU,驱逐。 然后,单击“map.eldest ()”; 因为是非标准API,所以修正了。

好的,看代码吧。

首先,我们来看看正确的Android6.0(APIlevel23 )实现。

//*

* removetheeldestentriesuntilthetotalofremainingentriesisator

* below the要求的大小。

*

* @ parammaxsizethemaximumsizeofthecachebeforereturning.maybe-1

* to evict even0-大小写元素。

*/

公共限制(int maxsize )。

while (真)。

key;

V value;

同步(this ) {

if(size0||(map.isempty ) ) size!=0) }

thrownewillegalstateexception (getclass ().getName ) )。

'.sizeof (isreportinginconsistentresults!' );

}

if(size=maxsize ) {

黑;

}

Map.Entry toEvict=map.eldest (;

if (to evict==空值) {

黑;

}

key=toEvict.getKey (;

value=toEvict.getValue (;

map.remove(key;

size-=safesizeof(key,value );

evictionCount;

}

实体移除(true,key,value,null );

}

}

其中包含map.eldest (; 方法表示取出LinkedHashMap中最年长的元素并驱逐。

让我们看看错误的实现Android5.0(APIlevel21 )。

//*

* @ parammaxsizethemaximumsizeofthecachebeforereturning.maybe-1

* to evict even0-大小写元素。

*/

权限限制(int maxsize )。

while (真)。

key;

V value;

同步(this ) {

if(size0||(map.isempty ) ) size!=0) }

thrownewillegalstateexception (getclass ().getName ) )。

'.sizeof (isreportinginconsistentresults!' );

}

if(size=maxsize ) {

黑;

}

//BEGIN LAYOUTLIB CHANGE

//getthelastiteminthelinkedlist。

//This is not ef

ficient, the goal here is to minimize the changes

// compared to the platform version.

Map.Entry toEvict = null;

for (Map.Entry entry : map.entrySet()) {

toEvict = entry;

}

// END LAYOUTLIB CHANGE

if (toEvict == null) {

break;

}

key = toEvict.getKey();

value = toEvict.getValue();

map.remove(key);

size -= safeSizeOf(key, value);

evictionCount++;

}

entryRemoved(true, key, value, null);

}

}

注意其中这段以及其注释说明:

Map.Entry toEvict = null;

for (Map.Entry entry : map.entrySet()) {

toEvict = entry;

}

遍历取出最后一个元素,这个正是将被驱逐的元素。同时在类说明中给了一段注释:

import java.util.LinkedHashMap;

import java.util.Map;

/**

* BEGIN LAYOUTLIB CHANGE

* This is a custom version that doesn't use the non standard LinkedHashMap#eldest.

* END LAYOUTLIB CHANGE

*

* A cache that holds strong references to a limited number of values. Each time

* a value is accessed, it is moved to the head of a queue. When a value is

* ...(略)

是说,这个版本不能使用非标准APILinkedHashMap#eldest。然而紧接着的一句话:

Each time a value is accessed, it is moved to the head of a queue.

每次访问一个值时,它都会被移动到队列的head(意思是说head是 most-recently,不是 least-recently)。

就说错了,有LinkedHashMap的文档为证:

* A special {@link #LinkedHashMap(int,float,boolean) constructor} is

* provided to create a linked hash map whose order of iteration is the order

* in which its entries were last accessed, from least-recently accessed to

* most-recently (access-order). This kind of map is well-suited to

* building LRU caches.

从“较远的近”(最近最少访问)到“极为最近”排序,说明head是“较远的近”,是 least-recently,是eldest。

这段代码经过测试,在Cache Size填满后,确实总是驱逐最后添加进去的元素。显然不符合Lru的意图。

需要注意的是,LruCache的map是这么构造的:this.map = new LinkedHashMap(0, 0.75f, true);,重点在这个true, 表示任何一个操作(get, put等)都将触发重排序,将这个被操作的元素排到链表的末尾,因此末尾的是最近“频繁”使用的,而不是 LRU(Least Recently Used)最近“最少”使用的,那么这个取出末尾的那个元素并将其驱逐的逻辑,显然是错误的!

那么我们还是回过头来看看eldest()到底做了什么吧!

/**

* Returns the eldest entry in the map, or {@code null} if the map is empty.

* @hide

*/

public Entry eldest() {

LinkedEntry eldest = header.nxt;

return eldest != header ? eldest : null;

}

eldest()直接返回了header.nxt.

public class LinkedHashMap extends HashMap {

/**

* A dummy entry in the circular linked list of entries in the map.

* The first real entry is header.nxt, and the last is header.prv.

* If the map is empty, header.nxt == header && header.prv == header.

*/

transient LinkedEntry header;

而header.nxt又是The first real entry. 意思很明确了,就是返回链表的第一个元素。

那么可以肯定Android 5.0(API Level 21)及以前对LruCache的实现就是一个bug了。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。