/* * Copyright (C) 2016 Peng fei Pan <sky@xiaopan.me> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package me.xiaopan.sketch.drawable; import android.graphics.Bitmap; import me.xiaopan.sketch.SLogType; import me.xiaopan.sketch.SLog; import me.xiaopan.sketch.cache.BitmapPoolUtils; import me.xiaopan.sketch.cache.BitmapPool; import me.xiaopan.sketch.util.SketchUtils; /** * 引用Bitmap,能够计算缓存引用、显示引用以及等待显示引用 */ public class RefBitmap extends SketchBitmap { private static final String LOG_NAME = "RefBitmap"; private int memoryCacheRefCount; // 内存缓存引用 private int displayRefCount; // 真正显示引用 private int waitingUseRefCount; // 等待使用引用 private BitmapPool bitmapPool; public RefBitmap(Bitmap bitmap, String key, String uri, ImageAttrs imageAttrs, BitmapPool bitmapPool) { super(bitmap, key, uri, imageAttrs); this.bitmapPool = bitmapPool; } public String getBitmapInfo() { if (isRecycled()) { return String.format("%s,%s", LOG_NAME, getKey()); } return String.format("%s,%dx%d,%s,%s,%d,%s", Integer.toHexString(bitmap.hashCode()), bitmap.getWidth(), bitmap.getHeight(), getAttrs().getMimeType(), bitmap.getConfig() != null ? bitmap.getConfig().name() : null, SketchUtils.getByteCount(bitmap), getKey()); } @Override public String getInfo() { if (isRecycled()) { return String.format("%s(Recycled,%s)", LOG_NAME, getKey()); } return String.format("%s(%s,%dx%d,%s,%s,%d,%s)", LOG_NAME, Integer.toHexString(bitmap.hashCode()), bitmap.getWidth(), bitmap.getHeight(), getAttrs().getMimeType(), bitmap.getConfig() != null ? bitmap.getConfig().name() : null, SketchUtils.getByteCount(bitmap), getKey()); } /** * 已回收? */ public synchronized boolean isRecycled() { return bitmap == null || bitmap.isRecycled(); } /** * 设置显示引用 * * @param callingStation 调用位置 * @param displayed 显示 */ public synchronized void setIsDisplayed(String callingStation, boolean displayed) { if (displayed) { displayRefCount++; referenceChanged(callingStation); } else if (displayRefCount > 0) { displayRefCount--; referenceChanged(callingStation); } } /** * 设置缓存引用 * * @param callingStation 调用位置 * @param cached 缓存 */ public synchronized void setIsCached(String callingStation, boolean cached) { if (cached) { memoryCacheRefCount++; referenceChanged(callingStation); } else if (memoryCacheRefCount > 0) { memoryCacheRefCount--; referenceChanged(callingStation); } } /** * 设置等待使用引用 * * @param callingStation 调用位置 * @param waitingUse 等待使用 */ public synchronized void setIsWaitingUse(String callingStation, boolean waitingUse) { if (waitingUse) { waitingUseRefCount++; referenceChanged(callingStation); } else if (waitingUseRefCount > 0) { waitingUseRefCount--; referenceChanged(callingStation); } } /** * 引用变化时执行此方法 * * @param callingStation 调用位置 */ private void referenceChanged(String callingStation) { if (isRecycled()) { if (SLogType.CACHE.isEnabled()) { SLog.e(SLogType.CACHE, LOG_NAME, "Recycled. %s. %s", callingStation, getKey()); } return; } if (memoryCacheRefCount == 0 && displayRefCount == 0 && waitingUseRefCount == 0) { if (SLogType.CACHE.isEnabled()) { SLog.w(SLogType.CACHE, LOG_NAME, "Free. %s. bitmap(%s)", callingStation, getBitmapInfo()); } BitmapPoolUtils.freeBitmapToPool(bitmap, bitmapPool); bitmap = null; } else { if (SLogType.CACHE.isEnabled()) { SLog.d(SLogType.CACHE, LOG_NAME, "Can't free. %s. references(%d,%d,%d). bitmap(%s)", callingStation, memoryCacheRefCount, displayRefCount, waitingUseRefCount, getBitmapInfo()); } } } }