Android 9.0(API 28) Resources管理源码分析

从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();
        }

打印出来的结果如下图

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值