android中Resources的资源缓存机制

来源:互联网 发布:遗传算法的过程 编辑:程序博客网 时间:2024/05/20 05:26

通过梳理下ImageView的setImageResource方法的调用流程,来看下android中Resources的资源缓存机制。

public void setImageResource(int resId) {        // The resource configuration may have changed, so we should always        // try to load the resource even if the resId hasn't changed.        final int oldWidth = mDrawableWidth;        final int oldHeight = mDrawableHeight;        updateDrawable(null);        mResource = resId;        mUri = null;        resolveUri();        if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {            requestLayout();        }        invalidate();    }
先调用updateDrawable将mDrawable置为null,然后调用resolveUri方法。

private void resolveUri() {        ... ...        if (mResource != 0) {            try {                d = mContext.getDrawable(mResource);            } catch (Exception e) {                Log.w("ImageView", "Unable to find resource: " + mResource, e);                // Don't try again.                mUri = null;            }        } else if (mUri != null) {            ... ...        } else {            ... ...        } else {            return;        }        updateDrawable(d);    }
resolveUri中会调用Context的getDrawable方法。

public final Drawable getDrawable(int id) {        return getResources().getDrawable(id, getTheme());    }
Context的getDrawable方法会间接调用Resources的getDrawable方法。

public Drawable getDrawable(int id, @Nullable Theme theme) throws NotFoundException {        TypedValue value;        synchronized (mAccessLock) {            value = mTmpValue;            if (value == null) {                value = new TypedValue();            } else {                mTmpValue = null;            }            getValue(id, value, true);        }        final Drawable res = loadDrawable(value, id, theme);        synchronized (mAccessLock) {            if (mTmpValue == null) {                mTmpValue = value;            }        }        return res;    }
最后会调用到Resources的loadDrawable方法,在看loadDrawable方法的具体流程之前,先看下Resources中用于缓存的相关数据结构。

    // Information about preloaded resources.  Note that they are not    // protected by a lock, because while preloading in zygote we are all    // single-threaded, and after that these are immutable.    private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;    private static final LongSparseArray<ConstantState> sPreloadedColorDrawables            = new LongSparseArray<ConstantState>();    private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists            = new LongSparseArray<ColorStateList>();
上面的数据结构是在zygote进程中预加载的,因为是无法改变的,所以没有加锁保护。

    private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mDrawableCache =            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();    private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache =            new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>();    private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache =            new LongSparseArray<WeakReference<ColorStateList>>();    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =            new ConfigurationBoundResourceCache<Animator>(this);    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =            new ConfigurationBoundResourceCache<StateListAnimator>(this);
上面的数据结构分别用来缓存不同类型的资源,下面来看下loadDrawable的具体流程。
Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {        ... ...        final boolean isColorDrawable;        final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches;        final long 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;        }        // First, check whether we have a cached version of this drawable        // that was inflated against the specified theme.        if (!mPreloading) {            final Drawable cachedDrawable = getCachedDrawable(caches, key, theme);            if (cachedDrawable != null) {                return cachedDrawable;            }        }        // Next, check preloaded drawables. These are unthemed but may have themeable attributes.        final ConstantState cs;        if (isColorDrawable) {            cs = sPreloadedColorDrawables.get(key);        } else {            cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);        }        final Drawable dr;        if (cs != null) {            final Drawable clonedDr = cs.newDrawable(this);            if (theme != null) {                dr = clonedDr.mutate();                dr.applyTheme(theme);                dr.clearMutated();            } else {                dr = clonedDr;            }        } else if (isColorDrawable) {            dr = new ColorDrawable(value.data);        } else {            dr = loadDrawableForCookie(value, id, theme);        }        // If we were able to obtain a drawable, store it in the appropriate        // cache (either preload or themed).        if (dr != null) {            dr.setChangingConfigurations(value.changingConfigurations);            cacheDrawable(value, theme, isColorDrawable, caches, key, dr);        }        return dr;    }
在loadDrawable方法中,首先会判断资源类型,根据不同的资源类型来查询不同的资源缓存数据结构,会依次调用getCachedDrawable,getCachedDrawableLocked,getConstantStateLocked来查询缓存,这些方法这里不详述。如果命中了缓存,则直接返回缓存;如果没有命中缓存,则先查询预加载的资源缓存,如果也没有命中,新建一个Drawable对象(如果isColorDrawable为true,则新建一个ColorDrawable对象,否则调用loadDrawableForCookie方法,从xml文件中新建Drawable对象),最后调用cacheDrawable方法缓存Drawable对象。

小结:经过上面对ImageView的setImageResource方法调用流程的梳理,简要地介绍了下android中Resources的缓存机制,不足之处希望大家指正。


0 0
原创粉丝点击