getDrawable()キャッシュによる問題
7432 ワード
私たちはよくgetContext()を通過します.getResources().getDrawable()は、Androidメカニズムでキャッシュメカニズムが使用されているため、直接setColorFilter()で色を変更すると、他のgetDrawable()の色も変更される可能性があります.私たちのプロジェクトではよく出会って、自分の画像がわけがわからずに他の色に変更されました.
まずgetDrawable()のソースコードを見てみましょう.
インタフェースsetColorFilterメソッドを見てみましょう
BitmapDrawableで
解決策はmutate法について述べました
結論
BitmapDrawable()をgetDrawable()で取得すると、色を変更するなど、いくつかのピットが埋め込まれます.mutateを調整したほうがいいです.もちろんnew BitmapDrawableも直接可能ですが、bitmapは多重化されず、メモリ消費が増大します.
まずgetDrawable()のソースコードを見てみましょう.
public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException {
......
drawable
final Drawable res = loadDrawable(value, id, theme);
synchronized (mAccessLock) {
if (mTmpValue == null) {
mTmpValue = value;
}
}
return res;
}
/*package*/ Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
if (TRACE_FOR_PRELOAD) {
// Log only framework resources
if ((id >>> 24) == 0x1) {
final String name = getResourceName(id);
if (name != null) {
Log.d("PreloadDrawable", name);
}
}
}
final boolean isColorDrawable;
final ArrayMap>> caches;
final long key;
//Drawable 2 ,colorDrawable( R.color.xxx) Drawable, key
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
isColorDrawable = true;
caches = mColorDrawableCache;
key = value.data;
} else {
isColorDrawable = false;
caches = mDrawableCache;
key = (((long) value.assetCookie) << 32) | value.data;
}
//
if (!mPreloading) {
final Drawable cachedDrawable = getCachedDrawable(caches, key, theme);
if (cachedDrawable != null) {
return cachedDrawable;
}
}
// ConstantState, BitmapState Bitmap Paint, ConstantState
final ConstantState cs;
if (isColorDrawable) {
cs = sPreloadedColorDrawables.get(key);
} else {
cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
}
//new drawable
final Drawable dr;
if (cs != null) {
final Drawable clonedDr = cs.newDrawable(this);
if (theme != null) {
dr = clonedDr.mutate();// , ConstantState
dr.applyTheme(theme);
dr.clearMutated();
} else {
dr = clonedDr;
}
} else if (isColorDrawable) {
// color,
dr = new ColorDrawable(value.data);
} else {
// drawable
dr = loadDrawableForCookie(value, id, theme);
}
// ConstantState
if (dr != null) {
dr.setChangingConfigurations(value.changingConfigurations);
cacheDrawable(value, theme, isColorDrawable, caches, key, dr);
}
return dr;
}
インタフェースsetColorFilterメソッドを見てみましょう
BitmapDrawableで
@Override
public void setColorFilter(ColorFilter cf) {
// State Oaint , State
mBitmapState.mPaint.setColorFilter(cf);
invalidateSelf();
}
解決策はmutate法について述べました
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
// BitmapState
mBitmapState = new BitmapState(mBitmapState);
mMutated = true;
}
return this;
}
//
BitmapState(BitmapState bitmapState) {
mBitmap = bitmapState.mBitmap;
mTint = bitmapState.mTint;
mTintMode = bitmapState.mTintMode;
mThemeAttrs = bitmapState.mThemeAttrs;
mChangingConfigurations = bitmapState.mChangingConfigurations;
mGravity = bitmapState.mGravity;
mTileModeX = bitmapState.mTileModeX;
mTileModeY = bitmapState.mTileModeY;
mTargetDensity = bitmapState.mTargetDensity;
mBaseAlpha = bitmapState.mBaseAlpha;
//Paint , Paint
mPaint = new Paint(bitmapState.mPaint);
mRebuildShader = bitmapState.mRebuildShader;
mAutoMirrored = bitmapState.mAutoMirrored;
}
結論
BitmapDrawable()をgetDrawable()で取得すると、色を変更するなど、いくつかのピットが埋め込まれます.mutateを調整したほうがいいです.もちろんnew BitmapDrawableも直接可能ですが、bitmapは多重化されず、メモリ消費が増大します.