LruCache 의 원리 와 사용

21214 단어 android기술.code
왜 LruCache 캐 시 를 사용 합 니까?
우선 캐 시 의 관건 적 인 절차 로 보고 저장,읽 기,청소 합 니 다.저장 과 읽 기의 차이 가 크 지 않 습 니 다.Lru 알고리즘 은 캐 시 를 만 드 는 것 과 일반적인 데이터 구 조 를 캐 시 하 는 것 이 가장 큰 차이 점 은 청소 정책 에 대한 처리 입 니 다.공간의 제한 으로 인해 모든 캐 시 는 청소 정책 이 필요 합 니 다.가장 간단 한 청소 정책 은 기한 이 지난 시간 과 최대 공간 을 정 하 는 것 입 니 다.최대 사용 공간 을 초과 하여 청소 절차 에 들 어가 야 합 니 다.또한 만 료 시간 이 지난 캐 시 내용 은 만 료 로 표시 되 어 청소 절차 에 들 어가 기 때문에 시간 필드 와 공간 최대 치 를 유지 해 야 합 니 다.물론 완벽 한 캐 시 를 실현 할 수 있 습 니 다.Lru 캐 시가 간단 한 점 은 그 가 만 료 된 시간 을 스스로 유지 하지 않 고 최대 공간 값 만 필요 하 다 는 것 이다.일부 데이터 구 조 를 통 해 매번 캐 시가 명중 되 거나 새로 추 가 된 데 이 터 를 교묘 하 게 맨 앞 에 놓 고 뒤의 데 이 터 는 장시간 사용 하지 않 은 데이터 로 침전 시 키 는 것 이 간단 하 다.그러나 맞 춤 형 과 유연성 이 비교적 떨 어 질 것 이다.예 를 들 어 이 공간의 최대 치 는 max Size 가 얼마나 정 하 느 냐 가 관건 이다.만약 에 너무 작고 데이터 의 양 이 많 으 면 이 lru 알고리즘 은 의 미 를 잃 게 된다.삭 제 될 수 있 는 데이터 도 얼마 전에 방 문 했 기 때문에 max Size 가 너무 크게 정 해 지면 공간 에 낭 비 를 초래 할 수 있다.개인 적 으로 일반적인 방법 보다 가장 큰 공간 이 작 을 것 이 라 고 생각 합 니 다.일반적인 방법 으로 가장 큰 공간 을 출발 할 때 많은 공간 을 차지 한 것 이 분명 합 니 다.그렇지 않 으 면 시간 을 사용 하여 관리 하면 조건 을 만족 시 킬 수 있 습 니 다.
LruCache 는 핫 이 슈 캐 시 에 대한 장점 이 비교적 크 고 일부 자주 여러 번 사용 하 는 데 이 터 는 효율 이 높다.예 를 들 어 이미지 캐 시,일부 첫 페이지 와 같은 그림 은 빈번 할 것 이다.두 번 째 페이지 의 우선 순위 가 높 지 않 으 면 이런 장면 이 비교적 적합 하 다.그러나 우발 적 으로 흩 어 진 데 이 터 는 주기 적 인 데이터 가 현저히 적합 하지 않다.
android sdk lrucache 원리
주로 LinkedHashMap 이라는 데이터 구 조 를 사 용 했 습 니 다.그 는 방문 순 서 를 사용 하여 데 이 터 를 저장 할 수 있 습 니 다.매번 put 와 get 데 이 터 를 사용 할 때 새로운 데 이 터 를 양 방향 링크 의 끝 에 놓 고 읽 기 편 하 며 자주 사용 하지 않 는 것 은 머리 에 점점 가 라 앉 습 니 다.
 public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
			//put  ,    get    。
            putCount++;
            //size            ,  sizeOf(key,value)     ,          1。
            size += safeSizeOf(key, value);
            previous = map.put(key, value);
            if (previous != null) {
            	//      ,      size
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
        	//      ,              ,       。
            entryRemoved(false, key, previous, value);
        }
		//          
        trimToSize(maxSize);
        return previous;
    }
 private int safeSizeOf(K key, V value) {
 		//      sizeOf
        int result = sizeOf(key, value);
        if (result < 0) {
            throw new IllegalStateException("Negative size: " + key + "=" + value);
        }
        return result;
    }

    /**
     *   key value        size,     ,     1
     */
    protected int sizeOf(K key, V value) {
        return 1;
    }
     /**
     *      size
     */
    public synchronized final int size() {
        return size;
    }
public final V get(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key);
            if (mapValue != null) {
	            //get  ,    get    。
                hitCount++;
                return mapValue;
            }
            missCount++;
        }
		
        /*            ,            ~
         * Attempt to create a value. This may take a long time, and the map
         * may be different when create() returns. If a conflicting value was
         * added to the map while create() was working, we leave that value in
         * the map and release the created value.
         * create       ,                      。
         */

        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;
            //    create  ,  key   ,      key create    
            mapValue = map.put(key, createdValue);
			//  create           ,           put key  ,  ,        put  
            if (mapValue != null) {
                // There was a conflict so undo that last put
                map.put(key, mapValue);
            } else {
                size += safeSizeOf(key, createdValue);
            }
        }

        if (mapValue != null) {
        	//           get  
            entryRemoved(false, key, createdValue, mapValue);
            return mapValue;
        } else {
        	//          
            trimToSize(maxSize);
            return createdValue;
        }
    }
    
    protected V create(K key) {
        return null;
    }
 //       maxSize    
 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!");
                }

                if (size <= maxSize) {
                    break;
                }

                // BEGIN LAYOUTLIB CHANGE
                // get the last item in the linked list.
                // This is not efficient, the goal here is to minimize the changes
                // compared to the platform version.
                Map.Entry<K, V> toEvict = null;
                for (Map.Entry<K, V> 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);
        }
    }

좋은 웹페이지 즐겨찾기