package com.camnter.newlife.ui.activity.lrucache; import android.annotation.TargetApi; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import butterknife.BindView; import butterknife.ButterKnife; import com.camnter.newlife.R; import com.camnter.newlife.core.activity.BaseAppCompatActivity; import com.camnter.newlife.utils.cache.LruCache; import java.math.BigDecimal; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; /** * Description:LruCacheActivity * Created by:CaMnter * Time:2016-04-21 20:48 */ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) public class LruCacheActivity extends BaseAppCompatActivity implements View.OnClickListener { private static final String LRU_CACHE_ENTRY_REMOVED_NULL_FORMAT = "entryRemoved:"; private static final String LRU_CACHE_RECENT_FORMAT = "Recent visit:%s"; private static final String LRU_CACHE_CACHE_DATA_FORMAT = "Cache data:%s"; private static final String LRU_CACHE_ENTRY_REMOVED_INFO_FORMAT = "entryRemoved:\nevicted: %1$s\nkey: %2$s\noldValue: %3$s\nnewValue: %4$s"; private static final float ONE_MIB = 1024 * 1024; // 7MB private static final int CACHE_SIZE = (int) (7 * ONE_MIB); private final Map<Bitmap, String> bitmap2Key = new HashMap<>(); private final List<String> recentList = new LinkedList<>(); private final List<String> cacheList = new LinkedList<>(); @BindView(R.id.camnter_size_text) TextView mCamnterSizeText; @BindView(R.id.camnter_count_text) TextView mCamnterCountText; @BindView(R.id.drakeet_size_text) TextView mDrakeetSizeText; @BindView(R.id.drakeet_count_text) TextView mDrakeetCountText; @BindView(R.id.ka_size_text) TextView mKaSizeText; @BindView(R.id.ka_count_text) TextView mKaCountText; @BindView(R.id.peter_size_text) TextView mPeterSizeText; @BindView(R.id.entryRemoved_info_text) TextView mEntryRemovedInfoText; @BindView(R.id.get_one) Button mGetOne; @BindView(R.id.get_two) Button mGetTwo; @BindView(R.id.get_three) Button mGetThree; @BindView(R.id.clear_remove_info) Button mClearRemoveInfo; @BindView(R.id.put_four) Button mPutFour; @BindView(R.id.camnter_hashCode_text) TextView mCamnterHashCodeText; @BindView(R.id.drakeet_hashCode_text) TextView mDrakeetHashCodeText; @BindView(R.id.ka_hashCode_text) TextView mKaHashCodeText; @BindView(R.id.peter_hashCode_text) TextView mPeterHashCodeText; @BindView(R.id.recent_info_text) TextView mRecentInfoText; @BindView(R.id.cache_data_text) TextView mCacheDataText; private LruCache<String, Bitmap> bitmapCache; private Bitmap camnterBitmap; private Bitmap drakeetBitmap; private Bitmap kaBitmap; private Bitmap peterBitmap; private int camnterCount = 0; private int drakeetCount = 0; private int kaCount = 0; /** * Fill in layout id * * @return layout id */ @Override protected int getLayoutId() { return R.layout.activity_lrucache; } /** * Initialize the view in the layout * * @param savedInstanceState savedInstanceState */ @Override protected void initViews(Bundle savedInstanceState) { ButterKnife.bind(this); } private void initBitmapAndText() { this.camnterBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_camnter); this.drakeetBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_drakeet); this.kaBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_kaede_akatsuki); this.peterBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_peter_cai); this.bitmap2Key.put(this.camnterBitmap, "<1>"); this.bitmap2Key.put(this.drakeetBitmap, "<2>"); this.bitmap2Key.put(this.kaBitmap, "<3>"); this.bitmap2Key.put(this.peterBitmap, "<4>"); this.mCamnterSizeText.setText(this.getString(R.string.lru_cache_size_format, new BigDecimal(this.camnterBitmap.getByteCount() / ONE_MIB).setScale(2, BigDecimal.ROUND_HALF_UP).toString())); this.mDrakeetSizeText.setText(this.getString(R.string.lru_cache_size_format, new BigDecimal(this.drakeetBitmap.getByteCount() / ONE_MIB).setScale(2, BigDecimal.ROUND_HALF_UP).toString())); this.mKaSizeText.setText(this.getString(R.string.lru_cache_size_format, new BigDecimal(this.kaBitmap.getByteCount() / ONE_MIB).setScale(2, BigDecimal.ROUND_HALF_UP).toString())); this.mPeterSizeText.setText(this.getString(R.string.lru_cache_size_format, new BigDecimal(this.peterBitmap.getByteCount() / ONE_MIB).setScale(2, BigDecimal.ROUND_HALF_UP).toString())); this.mCamnterCountText.setText( this.getString(R.string.lru_cache_count_format, this.camnterCount)); this.mDrakeetCountText.setText( this.getString(R.string.lru_cache_count_format, this.drakeetCount)); this.mKaCountText.setText(this.getString(R.string.lru_cache_count_format, this.kaCount)); this.mCamnterHashCodeText.setText( this.getString(R.string.lru_cache_hashcode_format, this.camnterBitmap.hashCode())); this.mDrakeetHashCodeText.setText( this.getString(R.string.lru_cache_hashcode_format, this.drakeetBitmap.hashCode())); this.mKaHashCodeText.setText( this.getString(R.string.lru_cache_hashcode_format, this.kaBitmap.hashCode())); this.mPeterHashCodeText.setText( this.getString(R.string.lru_cache_hashcode_format, this.peterBitmap.hashCode())); this.mEntryRemovedInfoText.setText(LRU_CACHE_ENTRY_REMOVED_NULL_FORMAT); this.mRecentInfoText.setText( String.format(Locale.getDefault(), LRU_CACHE_RECENT_FORMAT, "")); } private void initCache() { this.bitmapCache = new LruCache<String, Bitmap>(CACHE_SIZE) { protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } /** * 1.当被回收或者删掉时调用。该方法当value被回收释放存储空间时被remove调用 * 或者替换条目值时put调用,默认实现什么都没做。 * 2.该方法没用同步调用,如果其他线程访问缓存时,该方法也会执行。 * 3.evicted=true:如果该条目被删除空间 (表示 进行了trimToSize or remove) evicted=false:put冲突后 或 get里成功create后 导致 * 4.newValue!=null,那么则被put()或get()调用。 */ @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { mEntryRemovedInfoText.setText( String.format(Locale.getDefault(), LRU_CACHE_ENTRY_REMOVED_INFO_FORMAT, evicted, key, oldValue != null ? oldValue.hashCode() : "null", newValue != null ? newValue.hashCode() : "null")); // 见上述 3. if (evicted) { // 进行了trimToSize or remove (一般是溢出了 或 key-value被删除了 ) if (recentList.contains(key)) { recentList.remove(key); refreshText(mRecentInfoText, LRU_CACHE_RECENT_FORMAT, recentList); } } else { // put冲突后 或 get里成功create 后 recentList.remove(key); refreshText(mRecentInfoText, LRU_CACHE_RECENT_FORMAT, recentList); } if (cacheList.contains(key)) { cacheList.remove(key); refreshText(mCacheDataText, LRU_CACHE_CACHE_DATA_FORMAT, cacheList); } } }; this.bitmapCache.put(this.bitmap2Key.get(this.camnterBitmap), this.camnterBitmap); this.bitmapCache.put(this.bitmap2Key.get(this.drakeetBitmap), this.drakeetBitmap); this.bitmapCache.put(this.bitmap2Key.get(this.kaBitmap), this.kaBitmap); this.cacheList.add(this.bitmap2Key.get(this.camnterBitmap)); this.cacheList.add(this.bitmap2Key.get(this.drakeetBitmap)); this.cacheList.add(this.bitmap2Key.get(this.kaBitmap)); this.refreshText(this.mCacheDataText, LRU_CACHE_CACHE_DATA_FORMAT, this.cacheList); } /** * Initialize the View of the listener */ @Override protected void initListeners() { this.mGetOne.setOnClickListener(this); this.mGetTwo.setOnClickListener(this); this.mGetThree.setOnClickListener(this); this.mClearRemoveInfo.setOnClickListener(this); this.mPutFour.setOnClickListener(this); } /** * Initialize the Activity data */ @Override protected void initData() { this.initBitmapAndText(); this.initCache(); } /** * Called when a view has been clicked. * * @param v The view that was clicked. */ @Override public void onClick(View v) { boolean isGet = false; String key = null; switch (v.getId()) { case R.id.get_one: isGet = true; key = this.bitmap2Key.get(this.camnterBitmap); this.bitmapCache.get(key); this.mCamnterCountText.setText( this.getString(R.string.lru_cache_count_format, ++this.camnterCount)); break; case R.id.get_two: isGet = true; key = this.bitmap2Key.get(this.drakeetBitmap); this.bitmapCache.get(key); this.mDrakeetCountText.setText( this.getString(R.string.lru_cache_count_format, ++this.drakeetCount)); break; case R.id.get_three: isGet = true; key = this.bitmap2Key.get(this.kaBitmap); this.bitmapCache.get(key); this.mKaCountText.setText( this.getString(R.string.lru_cache_count_format, ++this.kaCount)); break; case R.id.put_four: this.bitmapCache.put(this.bitmap2Key.get(this.peterBitmap), this.peterBitmap); this.cacheList.add(this.bitmap2Key.get(peterBitmap)); this.refreshText(this.mCacheDataText, LRU_CACHE_CACHE_DATA_FORMAT, this.cacheList); break; case R.id.clear_remove_info: this.mEntryRemovedInfoText.setText(LRU_CACHE_ENTRY_REMOVED_NULL_FORMAT); break; } if (isGet) { if (this.recentList.contains(key)) { this.recentList.remove(key); } this.recentList.add(0, key); this.refreshText(this.mRecentInfoText, LRU_CACHE_RECENT_FORMAT, this.recentList); } } private void refreshText(TextView textView, String format, List<String> recentList) { Iterator<String> iterator = recentList.iterator(); String recentText = ""; while (iterator.hasNext()) { recentText += iterator.next() + " "; } textView.setText(String.format(Locale.getDefault(), format, recentText)); } }