Before checking the page startup time, I found one thing, this page set windowBackground in the style, the first time to start the page, found a getDrawable method took hundreds of milliseconds, the second time to enter only tens of milliseconds, exit the page, manual GC took hundreds of milliseconds. Decide to look at the onCreate process for AppCompatActivity.
AppCompatActivity:
@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {
final AppCompatDelegate delegate = getDelegate();
delegate.installViewFactory();
delegate.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}Copy the code
@NonNullpublic AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, this);
}
return mDelegate;
}Copy the code
GetDelegate () gets the AppCompateDelegateImpl class, and installViewFactory() sets the Factory2 method for LayoutInflater, which changes a set of controls to AppCompat controls
AppCompateDelegateImpl:
@Override
public void onCreate(Bundle savedInstanceState) {
mBaseContextAttached = true;
applyDayNight(false); ensureWindow(); // omit. mCreated =true;
}Copy the code
Mainly the ensureWidow method goes in and comes to the following method:
AppCompateDelegateImpl: private void attachToWindow(@nonnull Window Window) {// omit... final TintTypedArray a = TintTypedArray.obtainStyledAttributes( mContext, null, sWindowBackgroundStyleable); final Drawable winBg = a.getDrawableIfKnown(0);if(winBg ! = null) { // Nowset the background drawable
window.setBackgroundDrawable(winBg);
}
a.recycle();
mWindow = window;
}Copy the code
Get the windowBackground TypedArray, and then a.goetDrawableIfKnown (0) get the drawable (if any), fetch and cache should be in this method:
TintTypedArray:
public Drawable getDrawableIfKnown(int index) {
if (mWrapped.hasValue(index)) {
final int resourceId = mWrapped.getResourceId(index, 0);
if(resourceId ! = 0) {return AppCompatDrawableManager.get().getDrawable(mContext, resourceId, true); }}return null;
}Copy the code
AppCompatDrawableManager:
synchronized Drawable getDrawable(@NonNull Context context, @DrawableRes int resId,
boolean failIfNotKnown) {
return mResourceManager.getDrawable(context, resId, failIfNotKnown);
}Copy the code
ResourceManagerInternal: Private final WeakHashMap<Context, WeakHashMap<Context, LongSparseArray<WeakReference<ConstantState>>> mDrawableCaches = new WeakHashMap<>(0); synchronized Drawable getDrawable(@NonNull Context context, @DrawableRes int resId, boolean failIfNotKnown) { checkVectorDrawableSetup(context); / / here parsing vector, animated - vector, animated - the selector Drawable Drawable = loadDrawableFromDelegates (context, resId);ifDrawable = createDrawableIfNeeded(context, resId); }if (drawable == null) {
drawable = ContextCompat.getDrawable(context, resId);
}
if(drawable ! = null) { // Tint itif needed
drawable = tintDrawable(context, resId, failIfNotKnown, drawable);
}
if(drawable ! = null) { // Seeif we need to 'fix' the drawable
DrawableUtils.fixDrawable(drawable);
}
return drawable;
}Copy the code
ResourceManagerInternal: Private Drawable createDrawableIfNeeded(@nonNULL Context Context, @drawableres final int resId) {// omitted... final long key = createCacheKey(tv); Drawable Dr = getCachedDrawable(context, key);if(dr ! = null) { // If we got a cached drawable,return it
return dr;
}
// Else we need to try and create one...
dr = (this.mHooks == null) ? null
: this.mHooks.createDrawableFor(this, context, resId);
if(dr ! = null) { dr.setChangingConfigurations(tv.changingConfigurations); // Add drawable to the cache addDrawableToCache(context, key, Dr); }return dr;
}Copy the code
ResourceManagerInternal:
private synchronized Drawable getCachedDrawable(@NonNull final Context context,
final long key) {
final LongSparseArray<WeakReference<ConstantState>> cache = mDrawableCaches.get(context);
if (cache == null) {
return null;
}
final WeakReference<ConstantState> wr = cache.get(key);
if(wr ! = null) { // We have the key, and the secret ConstantState entry = wr.get();if(entry ! = null) {return entry.newDrawable(context.getResources());
} else{ // Our entry has been purged cache.delete(key); }}return null;
}Copy the code
Drawable (drawable); drawable (drawable); drawable (drawable); drawable (drawable); drawable (drawable) Each Drawable class is associated with a ConstantState class to hold constant data about the Drawable class. If a Drawable is created from the same RES, to save memory, They share the same ConstantState class object.
At this point, the drawable cache ends, and the GC might reclaim it due to weak references, but this cache should be used for more than just the Window background, so I looked around and found that almost all AppCompat controls use this cache.
Here is just a little bit of my understanding, if there is any mistake, I hope to point out.