Android 资源加载Resources源码分析(8.0)

我们熟悉的资源加载代码:

1.Activity.getResources();
2.Context.getResources();

这2种方式获取的都是Resources对象

先看第一种获取Resources对象源码分析:

说明:(AppcompatActivity中getResource()方法与Activity.getResources()是有区别的。AppcompatActivity是new Resources(...)对象)

一:Activity.getResources()源码分析:

Activity.getResources()之间调用的是Activity父类ContextThreadWrapper类中的

    @Override
    public Resources getResources() {
        return getResourcesInternal();

    }

    private Resources getResourcesInternal() {
        if (mResources == null) {
            if (mOverrideConfiguration == null) {
                mResources = super.getResources();//继续向上 调用mBase.getReources()方法。其中mBase是一个Context对象
            } else {
                final Context resContext = createConfigurationContext(mOverrideConfiguration);
                mResources = resContext.getResources();
            }
        }
        return mResources;
    }

从上面知道Activity.getResources() 其实也是调用的Context.getResources()方法

二:继续分析Context.getResources()方法。

Context是一个抽象类。其中getResources()方法源码:

public abstract Resources getResources()

通过查询资料知道:ContextImpl是Context的实现类。(这里我没有知道源码实现的地方)

ContextImpl源码地址:http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/android/app/ContextImpl.java

    @Override
    public Resources getResources() {
        return mResources;
    }

ContextImpl的getResources()方法中已实例化了Resources对象

mResources是通过setResources方法赋值:

    void setResources(Resources r) {
        if (r instanceof CompatResources) {
            ((CompatResources) r).setContext(this);
        }
        mResources = r;
    }

查找到给mResources赋值的代码:

 1     static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
 2         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
 3         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
 4                 null);
 5         context.setResources(packageInfo.getResources());
 6         return context;
 7     }
 8
 9     static ContextImpl createActivityContext(ActivityThread mainThread,
10             LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
11             Configuration overrideConfiguration) {
12         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
13
14         String[] splitDirs = packageInfo.getSplitResDirs();
15         ClassLoader classLoader = packageInfo.getClassLoader();
16
17         if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
18             Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
19             try {
20                 classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
21                 splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
22             } catch (NameNotFoundException e) {
23                 // Nothing above us can handle a NameNotFoundException, better crash.
24                 throw new RuntimeException(e);
25             } finally {
26                 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
27             }
28         }
29
30         ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
31                 activityToken, null, 0, classLoader);
32
33         // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
34         displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
35
36         final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
37                 ? packageInfo.getCompatibilityInfo()
38                 : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
39
40         final ResourcesManager resourcesManager = ResourcesManager.getInstance();
41
42         // Create the base resources for which all configuration contexts for this Activity
43         // will be rebased upon.
44         context.setResources(resourcesManager.createBaseActivityResources(activityToken,
45                 packageInfo.getResDir(),
46                 splitDirs,
47                 packageInfo.getOverlayDirs(),
48                 packageInfo.getApplicationInfo().sharedLibraryFiles,
49                 displayId,
50                 overrideConfiguration,
51                 compatInfo,
52                 classLoader));
53         context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
54                 context.getResources());
55         return context;
56     }

mResources赋值代码

分别调用的方法:

       一: context.setResources(packageInfo.getResources());
       二: context.setResources(resourcesManager.createBaseActivityResources(activityToken,
                packageInfo.getResDir(),
                splitDirs,
                packageInfo.getOverlayDirs(),
                packageInfo.getApplicationInfo().sharedLibraryFiles,
                displayId,
                overrideConfiguration,
                compatInfo,
                classLoader));

这里只分析第一种:(2种差不多。只是进入ResourcesManager方式不一样)

继续查看LoadedApk类的getResources()方法

    public Resources getResources() {
        if (mResources == null) {
            final String[] splitPaths;
            try {
                splitPaths = getSplitPaths(null);
            } catch (NameNotFoundException e) {
                // This should never fail.
                throw new AssertionError("null split not found");
            }

            mResources = ResourcesManager.getInstance().getResources(null, mResDir,
                    splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
                    Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
                    getClassLoader());
        }
        return mResources;
    }

继续查看ResourcesManager的getResources()方法

    public @Nullable 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 {
            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");//C的方法
            final ResourcesKey key = new ResourcesKey(//计算哈希值
                    resDir,
                    splitResDirs,
                    overlayDirs,
                    libDirs,
                    displayId,
                    overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
                    compatInfo);
            classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
            return getOrCreateResources(activityToken, key, classLoader);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
        }
    }

继续查看 getOrCreateResources()方法

 1     private @Nullable Resources getOrCreateResources(@Nullable IBinder activityToken,
 2             @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
 3         synchronized (this) {
 4             if (DEBUG) {
 5                 Throwable here = new Throwable();
 6                 here.fillInStackTrace();
 7                 Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here);
 8             }
 9
10             if (activityToken != null) {
11                 final ActivityResources activityResources =
12                         getOrCreateActivityResourcesStructLocked(activityToken);
13
14                 // Clean up any dead references so they don‘t pile up.
15                 ArrayUtils.unstableRemoveIf(activityResources.activityResources,
16                         sEmptyReferencePredicate);
17
18                 // Rebase the key‘s override config on top of the Activity‘s base override.
19                 if (key.hasOverrideConfiguration()
20                         && !activityResources.overrideConfig.equals(Configuration.EMPTY)) {
21                     final Configuration temp = new Configuration(activityResources.overrideConfig);
22                     temp.updateFrom(key.mOverrideConfiguration);
23                     key.mOverrideConfiguration.setTo(temp);
24                 }
25
26
27
28                 ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
29                 if (resourcesImpl != null) {
30                     if (DEBUG) {
31                         Slog.d(TAG, "- using existing impl=" + resourcesImpl);
32                     }
33                     return getOrCreateResourcesForActivityLocked(activityToken, classLoader,
34                             resourcesImpl, key.mCompatInfo);
35                 }
36
37                 // We will create the ResourcesImpl object outside of holding this lock.
38
39             } else {
40                 // Clean up any dead references so they don‘t pile up.
41                 ArrayUtils.unstableRemoveIf(mResourceReferences, sEmptyReferencePredicate);
42
43                 // Not tied to an Activity, find a shared Resources that has the right ResourcesImpl
44                 ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(key);
45                 if (resourcesImpl != null) {
46                     if (DEBUG) {
47                         Slog.d(TAG, "- using existing impl=" + resourcesImpl);
48                     }
49                     return getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
50                 }
51
52                 // We will create the ResourcesImpl object outside of holding this lock.
53             }
54         }
55
56         // If we‘re here, we didn‘t find a suitable ResourcesImpl to use, so create one now.
57         ResourcesImpl resourcesImpl = createResourcesImpl(key);
58         if (resourcesImpl == null) {
59             return null;
60         }
61
62         synchronized (this) {
63             ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
64             if (existingResourcesImpl != null) {
65                 if (DEBUG) {
66                     Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
67                             + " new impl=" + resourcesImpl);
68                 }
69                 resourcesImpl.getAssets().close();
70                 resourcesImpl = existingResourcesImpl;
71             } else {
72                 // Add this ResourcesImpl to the cache.
73                 mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
74             }
75
76             final Resources resources;
77             if (activityToken != null) {
78                 resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
79                         resourcesImpl, key.mCompatInfo);
80             } else {
81                 resources = getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);
82             }
83             return resources;
84         }
85     }

getOrCreateResources()方法

其中比较重要方法:

ResourcesImpl resourcesImpl = createResourcesImpl(key);
resources = getOrCreateResourcesLocked(classLoader, resourcesImpl, key.mCompatInfo);

先看:createResourcesImpl(key)方法,它去创建了一个ResourcesImpl对象

    private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
        final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
        daj.setCompatibilityInfo(key.mCompatInfo);

        final AssetManager assets = createAssetManager(key);
        if (assets == null) {
            return null;
        }

        final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
        final Configuration config = generateConfig(key, dm);
        final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);

        if (DEBUG) {
            Slog.d(TAG, "- creating impl=" + impl + " with key: " + key);
        }
        return impl;
    }

继续向下查看:getOrCreateResourcesLocked(..)方法

    private @NonNull Resources getOrCreateResourcesLocked(@NonNull ClassLoader classLoader,
            @NonNull ResourcesImpl impl, @NonNull CompatibilityInfo compatInfo) {
        // Find an existing Resources that has this ResourcesImpl set.
        final int refCount = mResourceReferences.size();
        for (int i = 0; i < refCount; i++) {
            WeakReference<Resources> weakResourceRef = mResourceReferences.get(i);
            Resources resources = weakResourceRef.get();
            if (resources != null &&
                    Objects.equals(resources.getClassLoader(), classLoader) &&
                    resources.getImpl() == impl) {
                if (DEBUG) {
                    Slog.d(TAG, "- using existing ref=" + resources);
                }
                return resources;
            }
        }

        // Create a new Resources reference and use the existing ResourcesImpl object.
        Resources resources = compatInfo.needsCompatResources() ? new CompatResources(classLoader)
                : new Resources(classLoader);
        resources.setImpl(impl);
        mResourceReferences.add(new WeakReference<>(resources));
        if (DEBUG) {
            Slog.d(TAG, "- creating new ref=" + resources);
            Slog.d(TAG, "- setting ref=" + resources + " with impl=" + impl);
        }
        return resources;
    }

到这里可以之间看到 Resources 对象是之间通过new Resources(ClassLoader)创建的

然后通过resources.setImpl(impl)去设置参数。

我们进一步去查看Resources.getString(int id)方法

    @NonNull
    public String getString(@StringRes int id) throws NotFoundException {
        return getText(id).toString();
    }
    public CharSequence getText(@StringRes int id, CharSequence def) {
        CharSequence res = id != 0 ? mResourcesImpl.getAssets().getResourceText(id) : null;
        return res != null ? res : def;
    }

这里发现加载资源是通过ResourcesImpl对象去加载的

    public AssetManager getAssets() {
        return mAssets;
    }

进一步查看AssetManager.getResourceText(int id)方法

    @Nullable
    final CharSequence getResourceText(@StringRes int resId) {
        synchronized (this) {
            final TypedValue outValue = mValue;
            if (getResourceValue(resId, 0, outValue, true)) {
                return outValue.coerceToString();
            }
            return null;
        }
    }
    final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
            boolean resolveRefs) {
        synchronized (this) {
            final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
            if (block < 0) {
                return false;
            }

            // Convert the changing configurations flags populated by native code.
            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
                    outValue.changingConfigurations);

            if (outValue.type == TypedValue.TYPE_STRING) {
                outValue.string = mStringBlocks[block].get(outValue.data);
            }
            return true;
        }
    }

继续往下 基本就是底层的一些东西了。

总结:Android 资源加载 核心就是AssetManager对象。

(后面写的不是特别详细。。。)

原文地址:https://www.cnblogs.com/kangqi001/p/8381355.html

时间: 2024-10-07 06:13:36

Android 资源加载Resources源码分析(8.0)的相关文章

spring启动component-scan类扫描加载过程---源码分析

有朋友最近问到了 spring 加载类的过程,尤其是基于 annotation 注解的加载过程,有些时候如果由于某些系统部署的问题,加载不到,很是不解!就针对这个问题,我这篇博客说说spring启动过程,用源码来说明,这部分内容也会在书中出现,只是表达方式会稍微有些区别,我将使用spring 3.0的版本来说明(虽然版本有所区别,但是变化并不是特别大),另外,这里会从WEB中使用spring开始,中途会穿插自己通过newClassPathXmlApplicationContext 的区别和联系.

ElasticSearch 启动时加载 Analyzer 源码分析

ElasticSearch 启动时加载 Analyzer 源码分析 本文介绍 ElasticSearch启动时如何创建.加载Analyzer,主要的参考资料是Lucene中关于Analyzer官方文档介绍.ElasticSearch6.3.2源码中相关类:AnalysisModule.AnalysisPlugin.AnalyzerProvider.各种Tokenizer类和它们对应的TokenizerFactory.另外还参考了一个具体的基于ElasticSearch采用HanLP进行中文分词的

jQuery实现DOM加载方法源码分析

传统的判断dom加载的方法 使用 dom0级 onload事件来进行触发所有浏览器都支持在最初是很流行的写法 我们都熟悉这种写法: window.onload=function(){ ... }  但是onload事件触发过于缓慢,尤其是在存在很多外部图片或者视频文件的时候,为了更好的了解这一点有必要知道一个html文档是如何进行加载的,这里引用一个园友的表述: 1.用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件: 2.浏览器开始载入htm

SpringMVC加载WebApplicationContext源码分析

from http://blessht.iteye.com/blog/2121845 Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC源码分析介绍它的核心实现原理. Tomcat服务器启动入口文件是web.xml,通过在其中配置相关的Listener和Servlet即可加载Spring MVC所需数据.基于Spring MVC最简单的配置如下.

Android编程之Fragment动画加载方法源码详解

上次谈到了Fragment动画加载的异常问题,今天再聊聊它的动画加载loadAnimation的实现源代码: Animation loadAnimation(Fragment fragment, int transit, boolean enter, int transitionStyle) { 接下来具体看一下里面的源码部分,我将一部分一部分的讲解,首先是: Animation animObj = fragment.onCreateAnimation(transit, enter, fragm

Android App 启动时显示正在加载图片(源码)

微信.QQ.天天动听等程序,在打开时显示了一张图片,然后跳转到相关界面.本文实现这个功能,其实很简单.... 新建两个Activity,LoadingActivity,MainActivity,将LoadingActivity设置为android.intent.action.MAIN.使用TimerTesk,或者Thread将LoadingActivity显示几秒后跳转到MainActivity界面. LoadingActivity: new Timer().schedule(new Timer

Android Small插件化框架源码分析

Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github.com/wequick/Small 插件化的方案,说到底要解决的核心问题只有三个: 1.1 插件类的加载 这个问题的解决和其它插件化框架的解决方法差不多.Android的类是由DexClassLoader加载的,通过反射可以将插件包动态加载进去.Small的gradle插件生成的是.so包,在初始

Android之rild进程启动源码分析

Android 电话系统框架介绍 在android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP.AP与BP之间有两种通信方式: 1.Solicited Response:Ap向Bp发送请求,Bp给Ap发送回复,该类型的AT指令及其回调函数以数组的形式存放在Ril_commands.h文件中: {数组中的索引号,请求回调函数,响应回调函数} [plain] view plaincopy {0, NULL, NULL},      

android-----Volley框架使用ImageLoader加载图片源码分析

上一篇我们分析了Volley框架的源码,知道了使用Volley框架的三个步骤,如果你对此还不是很熟,建议能看看上一篇博文:android-----Volley框架源码分析,这篇我们将首先使用Volley框架的ImageLoader来实现加载图片的功能,接着从源码角度来分析加载流程: 使用ImageLoader来加载图片步骤: (1)创建一个RequestQueue对象: (2)创建一个ImageLoader对象: (3)获取一个ImageListener对象(通过ImageLoader的getI