从Android7.0开始Google对Resources这一块做了一个较大的调整
今天我们挑取Android9.0的源码看下
先看Resources.java
相比于Android6.0 Resources中不在维护AssertManager 而是将AssertManager与其他的一些缓存 封装成了一个ResourcesImpl
看下源码
public class Resources {
static final String TAG = "Resources";
static Resources mSystem = null;
private ResourcesImpl mResourcesImpl;
private TypedValue mTmpValue = new TypedValue();
final ClassLoader mClassLoader;
}
public class ResourcesImpl {
private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables = new LongSparseArray<>();
private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>> sPreloadedComplexColors = new LongSparseArray<>();
// These are protected by mAccessLock.
private final Configuration mTmpConfig = new Configuration();
private final DrawableCache mDrawableCache = new DrawableCache();
private final DrawableCache mColorDrawableCache = new DrawableCache();
private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache = new ConfigurationBoundResourceCache<>();
private final ConfigurationBoundResourceCache<Animator> mAnimatorCache = new ConfigurationBoundResourceCache<>();
private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache = new ConfigurationBoundResourceCache<>();
final AssetManager mAssets;
private final DisplayMetrics mMetrics = new DisplayMetrics();
private final DisplayAdjustments mDisplayAdjustments;
private PluralRules mPluralRule;
private final Configuration mConfiguration = new Configuration();
}
ResourcesImpl 承担着老版本里面Resources的职责, 包装AssertManager 和 维护数据缓存
而Resources的代码也变的更加简单,其方法调用最终都是交给了ResourcesImpl来实现
不变的是Resources的管理还是要交给ResourcesManager来管理的,跟Android6.0一样ResourcesManager是一个单例模式
那么9.0的ResourcesManager与6.0的ResourcesManager有和不同?
还是从应用启动开始看起,还是熟悉的ContextImpl
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null);
context.setResources(packageInfo.getResources());
return context;
}
static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) {
。。。。。。。。
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName, activityToken, null, 0, classLoader);
final ResourcesManager resourcesManager = ResourcesManager.getInstance();
context.setResources(resourcesManager.createBaseActivityResources(activityToken, packageInfo.getResDir(), splitDirs, packageInfo.getOverlayDirs(), packageInfo.getApplicationInfo().sharedLibraryFiles, displayId, overrideConfiguration, compatInfo, classLoader));
context.mDisplay = resourcesManager.getAdjustedDisplay(displayId, context.getResources());
return context;
}
无论是生成Application的Resource还是生成Activity的Resource最终调用的是ResourceManager中的方法区别在于一个调用的是 ResourcesManager.getInstance().getResources 另一个调用的是resourcesManager.createBaseActivityResources
OK 我们看一下ResourcesManager的源码
先看下它提供的各种属性,我们挑重要的放上来,以免东西太多乱七八糟反而乱了阵脚
/**
* ResourceImpls及其配置的映射。 这些都是占用较大内存的数据
* 应该尽可能重用。所有的由ResourcesManager生成的ResourcesImpl都会被缓存在这个map中
*/
private final ArrayMap<ResourcesKey, WeakReference<ResourcesImpl>> mResourceImpls = new ArrayMap<>();
/**
*可以重用的资源引用列表。注意一下 这个list里面存储的并不是Activity的Resources缓存,按照我的理解,所有非Activcity的Resource都会被缓存在此处,比如Application的Resource
*/
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
/**
* 每个Activity都有一个基本覆盖配置,该配置应用于每个Resources对象,而这些对象又可以指定自己的覆盖配置。
这个缓存里面保存的都是Actrivity的Resource的缓存,ActivityResources是一个对象,里面包含了一个Activity所拥有的Configuration和所有可能拥有过的Resources,比如一个Activity,在某些情况下他的ResourcesImpl发生了变化,那么这个时候就ActivityResources就可能会持有多个Resource引用
*/
private final WeakHashMap<IBinder, ActivityResources> mActivityResourceReferences = new WeakHashMap<>();
/**
* 缓存的ApkAssets,这个可以先不看
*/
private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(3);
/**
* 这也是ApkAssets的一个缓存 这个也可以先不看
*/
private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>();
private static class ApkKey {
public final String path;
public final boolean sharedLib;
public final boolean overlay;
}
/**
* 与Activity关联的资源和基本配置覆盖。
*/
private static class ActivityResources {
public final Configuration overrideConfig = new Configuration();
//按照常规的理解 一个Activity只有一个Resources 但是这里却使用了一个list来存储,这是考虑如果Activity发生变化,重新生成了Resource,这个列表就会将Activity历史使用过的Resources都存在里面,当然,如果没有人再持有这些Resources,就会被回收
public final ArrayList<WeakReference<Resources>> activityResources = new ArrayList<>();
}
了解了这些重要的属性之后,我们再来看一下ResourceManager提供的诸多方法
ResourceManager提供了如下以写public方法供调用
先看getResources和createBaseActivityResources 最终都是使用一个ResourcesKey去调用getOrCreateResources
Resources getResources(@Nullable IBinder activityToken, @Nullable String resDir, @Nullable String[] splitResDirs, @Nullable String[] overlayDirs, @Nullable String[] libDirs, int displayId, @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) {
try {
final ResourcesKey key = new ResourcesKey(resDir, splitResDirs, overlayDirs, libDirs, displayId, overrideConfig != null ? new Configuration(overrideConfig) : null,compatInfo);
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
return getOrCreateResources(activityToken, key, classLoader);
} finally {
}
}
Resources createBaseActivityResources(@NonNull IBinder activityToken, @Nullable String resDir, @Nullable String[] splitResDirs, @Nullable String[] overlayDirs, @Nullable String[] libDirs, int displayId, @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) {
try {
final ResourcesKey key = new ResourcesKey(resDir, splitResDirs, overlayDirs, libDirs, displayId, overrideConfig != null ? new Configuration(overrideConfig) : null, compatInfo);
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
synchronized (this) {
// 强制创建ActivityResources对象并放到缓存里面
getOrCreateActivityResourcesStructLocked(activityToken);
}
// 更新任何现有的Activity Resources引用。
updateResourcesForActivity(activityToken, overrideConfig, displayId, false /* movedToDifferentDisplay */);
// 现在请求一个实际的Resources对象。
return getOrCreateResources(activityToken, key, classLoader);
} finally {
}
}
getOrCreateResources 我在各行代码处都写了注释,大家注意看代码中的注释,部分注释是对代码中引文注释的翻译
private @Nullable
Resources getOrCreateResources(@Nullable IBinder activityToken, @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
synchronized (this) {
if (activityToken != null) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(activityToken);
// 清理已经被回收的缓存
ArrayUtils.unstableRemoveIf(activityResources.activityResources, sEmptyReferencePredicate);
// Rebase the key's override config on top of the Activity's base override.
if (key.hasOverrideConfiguration() && !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
final Configuration temp = new Configuration(activityResources.overrideConfig);
temp.updateFrom(key.mOverrideConfiguration);
key.mOverrideConfiguration.setTo(temp);
}
//根据对应的key 去获取一个ResourcesImpl 有可能是新的也有可能是缓存里面的
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
if (resourcesImpl != null) {
//使用ResourcesImpl 去生成一个Resources
return getOrCreateResourcesForActivityLocked(activityToken, classLoader, resourcesImpl, key.mCompatInfo);
}
// We will create the ResourcesImpl object outside of holding this lock.
} else {
// 清理 因为mResourceReferences里面放的都是弱引用,要判断这些弱引用是否都已经被释放,如果释放的话就要从Array里面移除掉
ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
// 不依赖于Activity,找到具有正确ResourcesImpl的共享资源 这里就是根据key去mResourceImpls的缓存里面找
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
if (resourcesImpl != null) {
//如果找到resourcesImpl的话就去从mResourceReferences看有没有可用的resources 如果类加载器和ResourcesImpl相同,则获取现有的Resources对象,否则会创建一个新的Resources对象。
return getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
}
// 我们将在持有此锁之外创建ResourcesImpl对象。
}
// 如果我们走到了这里,我们找不到合适的ResourcesImpl来使用,所以现在创建一个。
ResourcesImpl resourcesImpl = createResourcesImpl(key);
if (resourcesImpl == null) {
return null;
}
// 将此ResourcesImpl添加到缓存中。
mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
final Resources resources;
if (activityToken != null) {
//从mActivityResourceReferences 里面去找 看有没有合适的Resources可用 如果没有就构建一个Resources兵添加到mActivityResourceReferences里面
resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader, resourcesImpl, key.mCompatInfo);
} else {
//使用创建出来的ResourcesImpl去匹配一个Resource,具体是从缓存mResourceReferences里面取(如果有的话)还是创建新的由下面的方法决定
resources = getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
}
return resources;
}
}
画个流程图看下
看完这个图基本上大体的逻辑就通了
我们使用如下的代码 hook 系统ResourcesManger的几个缓存 看一下当一个App启动并且打开一个Activity时,这些缓存里面都包含了哪些对象
try {
System.out.println("Application = " + getApplicationContext().getResources() + " 持有 " + Reflector.with(getApplicationContext().getResources()).method("getImpl").call());
System.out.println("Activity = " + getResources() + " 持有 " + Reflector.with(getResources()).method("getImpl").call());
System.out.println("System = " + Resources.getSystem() + " 持有 " + Reflector.with(Resources.getSystem()).method("getImpl").call());
ResourcesManager resourcesManager = ResourcesManager.getInstance();
System.out.println("--------------------------------mResourceImpls----------------------------------------------");
ArrayMap<ResourcesKey, WeakReference<ResourcesImpl>> mResourceImpls = Reflector.with(resourcesManager).field("mResourceImpls").get();
Iterator<ResourcesKey> resourcesKeyIterator = mResourceImpls.keySet().iterator();
while (resourcesKeyIterator.hasNext()) {
ResourcesKey key = resourcesKeyIterator.next();
WeakReference<ResourcesImpl> value = mResourceImpls.get(key);
System.out.println("key = " + key);
System.out.println("value = " + value.get());
}
System.out.println("-----------------------------------mResourceReferences-------------------------------------------");
ArrayList<WeakReference<Resources>> mResourceReferences = Reflector.with(resourcesManager).field("mResourceReferences").get();
for (WeakReference<Resources> weakReference : mResourceReferences) {
Resources resources = weakReference.get();
if (resources != null) {
System.out.println(resources + " 持有 " + Reflector.with(resources).method("getImpl").call());
}
}
System.out.println("-------------------------------------mActivityResourceReferences-----------------------------------------");
WeakHashMap<IBinder, Object> mActivityResourceReferences = Reflector.with(resourcesManager).field("mActivityResourceReferences").get();
Iterator<IBinder> iBinderIterator = mActivityResourceReferences.keySet().iterator();
while (iBinderIterator.hasNext()) {
IBinder key = iBinderIterator.next();
Object value = mActivityResourceReferences.get(key);
System.out.println("key = " + key);
System.out.println("value = " + value);
Object overrideConfig = Reflector.with(value).field("overrideConfig").get();
System.out.println("overrideConfig = " + overrideConfig);
Object activityResources = Reflector.with(value).field("activityResources").get();
try {
ArrayList<WeakReference<Resources>> list = (ArrayList<WeakReference<Resources>>) activityResources;
for (WeakReference<Resources> weakReference : list) {
Resources resources = weakReference.get();
System.out.println("activityResources = " + resources + " 持有 " + Reflector.with(resources).method("getImpl").call());
}
} catch (Reflector.ReflectedException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
打印出来的结果如下图