<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                文檔處理控制欄: * [x] 選題收集: * [ ] 初稿整理: * [ ] 補充校對: * [ ] 入庫存檔: --- --- # First 先看源碼,再用具體的demo加以驗證,我們先看一下這個LruCache這個類的大致結構和方法,如下圖所示: ![image.png](https://user-gold-cdn.xitu.io/2017/12/19/1606e1dfd1407543?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 這又是 get(K),put(K,V), remove(K) 的方法的 給人的感覺就像是一個Map的集合嘛,又有Key ,又有value 的,再看下具體的代碼: ~~~ public class LruCache<K, V> { private final LinkedHashMap<K, V> map; /** Size of this cache in units. Not necessarily the number of elements. */ private int size; private int maxSize; private int putCount; private int createCount; private int evictionCount; private int hitCount; private int missCount; /** * @param maxSize for caches that do not override {@link #sizeOf}, this is * the maximum number of entries in the cache. For all other caches, * this is the maximum sum of the sizes of the entries in this cache. */ public LruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap<K, V>(0, 0.75f, true); } ~~~ 看到開頭,我們就明白了,哦原來這個LruCache類中維護一個LinkedHashMap的一個集合,緩存我們這個對象,而且構造方法里需要我們傳入一個`maxSize`的一個值,根據上面的注釋我們就明白了這個就是我們LruCache緩存對象的最大數目。 # 有什么用呢? 根據慣性思維,我們可以認為,在`put`新的緩存對象的時候,根據我們設定的最大值`remove`集合里的某些緩存對象,進而添加新的緩存對象。 # Second 根據我們的分析,我們有必要去看一下這個`put`方法的源碼: ~~~ /** * 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); previous = map.put(key, value); if (previous != null) { size -= safeSizeOf(key, previous); } } if (previous != null) { entryRemoved(false, key, previous, value); } trimToSize(maxSize); return previous; } ~~~ 代碼量也不是特別多,我們看下這個,在這個`synchronized`同步代碼塊里,我們看到這個 `size`,是對put進來緩存對象個數的累加,然后調用集合的`map.put`方法,返回一個對象 `previous` ,就是判斷這個集合中是否添加了這個緩存對象,如果不為null,就對`size`減回去。 最后又調用一個 `trimToSize(maxSize)`方法,上面都是對添加一些邏輯的處理,那么不可能無限制添加啊,肯定有移除操作,那么我們推測這個邏輯可能在這個`trimToSize(maxSize)` 里處理。 源碼如下: ~~~ /** * Remove the eldest entries until the total of remaining entries is at or * below the requested size. * * @param maxSize the maximum size of the cache before returning. May be -1 * to evict even 0-sized elements. */ public 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 就結束循環 if (size <= maxSize || map.isEmpty()) { break; } // 獲取這個對象,然后從map中移除掉,保證size<=maxSize Map.Entry<K, V> toEvict = map.entrySet().iterator().next(); key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= safeSizeOf(key, value); evictionCount++; } entryRemoved(true, key, value, null); } } ~~~ 注釋:`Remove the eldest entries until the total of remaining entries is at or below the requested size` 大概意思是說:清除時間最久的對象直到剩余緩存對象的大小小于設置的大小。沒錯是我們想找的。 **這里說明一下:maxSize就是我們在構造方法里傳入的,自己設置的** ~~~ public LruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap<K, V>(0, 0.75f, true); } ~~~ 這樣LruCache的核心方法 `trimToSize`方法我們就說完了,接下來我將通過實例再次驗證下: # 設置場景 > 假設我們設置maxSize 為2,布局里顯示3個imageView,分別代表3張我們要顯示的圖片,我們添加3張圖片,看看會不會顯示3張? xml布局顯示如下(代碼就不貼了,很簡單): ![image.png](https://user-gold-cdn.xitu.io/2017/12/19/1606e1dfca963ed7?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) activity代碼如下: ~~~ public final int MAX_SIZE = 2; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_lru); ImageView iv1 = (ImageView) findViewById(R.id.iv1); ImageView iv2 = (ImageView) findViewById(R.id.iv2); ImageView iv3 = (ImageView) findViewById(R.id.iv3); Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(),R.drawable.bg); Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(),R.drawable.header_img); Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher); LruCache<String,Bitmap> lruCache = new LruCache<>(MAX_SIZE); lruCache.put("1",bitmap1); lruCache.put("2",bitmap2); lruCache.put("3",bitmap3); Bitmap bitmap = lruCache.get("1"); iv1.setImageBitmap(bitmap); Bitmap b2 = lruCache.get("2"); iv2.setImageBitmap(b2); Bitmap b3 = lruCache.get("3"); iv3.setImageBitmap(b3); } ~~~ 圖: ![bg.png](https://user-gold-cdn.xitu.io/2017/12/19/1606e1dfc83dd3d1?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) ![header_img.png](https://user-gold-cdn.xitu.io/2017/12/19/1606e1dfcaf75381?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) ![ic_launcher.png](https://user-gold-cdn.xitu.io/2017/12/19/1606e1dfc8d441e2?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 我們可以先嘗試分析一下:因為我們設置的MaxSize 是2 ,那么在put第三個Bitmap的時候,在`trimToSize`方法中,發現這個size是3 ,maxSize 是2,會繼續向下執行,不會break,結合下面代碼看下 ~~~ public 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 是3,maxSize 是 2 //第二次循環,此時 size 是 2 ,maxSize 是 2 ,滿足條件,break,結束循環 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 = 2,減去移除的元素 size -= safeSizeOf(key, value); evictionCount++; } entryRemoved(true, key, value, null); } } ~~~ 這個 `safeSizeOf` 是調用`sizeOf`方法。 那么也就是說,我們在`put`第三個`bitmap`的時候,`LruCache` 會自動幫我們移除掉第一個緩存對象,因為第一個最先添加進去,時間也最長,當然后添加的`bitmap`就是新的,最近的,那么我們推斷這個`iv1`是顯示不出圖片的,因為被移除掉了,其它剩余兩個可以顯示,分析就到這里,看下運行結果是不是跟我們分析的一樣: ![result.png](https://user-gold-cdn.xitu.io/2017/12/19/1606e1dfc843777c?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 哇!真的跟我們想的一樣耶,證明我們想的是對的。這里我們思考一下就是為什么`LruCache`使用了這個`LinkedHashMap`,為什么`LinkedHashMap`的創造方法跟我們平時創建的不太一樣,源碼是這樣的: ~~~ public LruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } this.maxSize = maxSize; this.map = new LinkedHashMap<K, V>(0, 0.75f, true); } ~~~ > 這里說一下評論里 `藏地情人`評論是:`new LinkedHashMap<K, V>(0, 0.75f, true)`這句代碼表示,初始容量為零,`0.75`是加載因子,表示容量達到最大容量的`75%`的時候會把內存增加一半。最后這個參數至關重要。表示訪問元素的排序方式,`true`表示按照訪問順序排序,`false`表示按照插入的順序排序。這個設置為`true`的時候,如果對一個元素進行了操作`(put、get)`,就會把那個元素放到集合的最后。 確實也是這樣的,我們看下`LinkedHashMap`的源碼: ~~~ /** * Constructs an empty <tt>LinkedHashMap</tt> instance with the * specified initial capacity, load factor and ordering mode. * * @param initialCapacity the initial capacity * @param loadFactor the load factor * @param accessOrder the ordering mode - <tt>true</tt> for * access-order, <tt>false</tt> for insertion-order * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; } ~~~ 里面這個`assessOrder` 注釋里也說的很明白:`the ordering mode - <tt>true</tt> for * access-order, <tt>false</tt> for insertion-order` -> `true` 呢就表示會排序,`false` 就代表按照插入的順序。默認不傳就是 `false` ,而且我們每次 `get(K) put(K,V)` 的時候 會根據這個變量調整元素在集合里的位置。而這么做的目的也只有一個:保留最近使用的緩存對象,舉個例子說明一下: 我們向這個集合里添加了三種元素 ~~~ LruCache<String, Bitmap> lruCache = new LruCache<>(MAX_SIZE);(MAX_SIZE=2) lruCache.put("1", bitmap1); lruCache.put("2", bitmap2); lruCache.put("3", bitmap3); ~~~ 此時它們在集合里的順序是這樣的: ![order.png](https://user-gold-cdn.xitu.io/2017/12/20/16071cd63863b74a?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 那比如說我們在`put` 3 元素之前,使用了1元素,就是調用了`get("1")`方法,我們知道LinkedHashMap就會改變鏈表里元素的存儲順序,代碼是這樣的: ~~~ lruCache.put("1", bitmap1); lruCache.put("2", bitmap2); lruCache.get("1"); lruCache.put("3", bitmap3); ~~~ ~~~ 那么此時對應鏈表里的順序就是: ~~~ ![image.png](https://user-gold-cdn.xitu.io/2017/12/20/16071cd6388b79d4?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 當我們再調用顯示的時候,循環遍歷就會優先把第一個位置的`key = "2"` 的緩存對象移除掉,保證了最近使用的原則,當然了因為把這個`max_size = 2`所以在我們執行`lruCache.put("3", bitmap3);` 時,集合最終會變成這樣: ![result.png](https://user-gold-cdn.xitu.io/2017/12/20/16071cd63a829568?imageView2/0/w/1280/h/960/format/webp/ignore-error/1) 集合里只剩下 `1 ,3`對應的緩存對象。 至此,LruCache就說完了,如果看完的你有不明白的地方可以留言,一起討論下~ --- 參考文章 * [LRU算法還一知半解?](https://juejin.im/post/5a38dca06fb9a0451f31104b)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看