android资源加载流程,Android资源加载过程简要分析

1、相关类图

9f7021a08483

QQ截图20160818093629.png

这里主要说明一下,为什么Resources和AssetManager都有一个mSystem属性和getSystem()方法,这是因为我们的应用不但要使用我们自己的资源,还要使用系统资源,也就是framework-res.apk中的资源,所以这里的mSystem是用来获取系统资源的。

2、初始化过程

在Activity启动过程中了解到,当zogyte进程fork一个应用进程用于运行子进程时,会跳转到ActivityThread.main()中进行一系列操作,这其中有一步就是创建应用程序运行的上下文环境ContextImpl:

ActivityThread.ApplicationThread.handleBindApplication()

private void handleBindApplication(AppBindData data) {

//..........

// Context初始化(ContextImpl)

final ContextImpl appContext = ContextImpl.createAppContext(this/*ActivityThread*/, data.info/*LoadedApk*/);

//........

}

/**

*ActivityThread mainThread = mainThread

*LoadedApk packageInfo = packageInfo

*boolean restricted = false

*int createDisplayWithId = Display.INVALID_DISPLAY

*/

private ContextImpl(ContextImpl container, ActivityThread mainThread,

LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,

Display display, Configuration overrideConfiguration, int createDisplayWithId) {

//.......

// LoadedApk赋值

mPackageInfo = packageInfo;

mResourcesManager = ResourcesManager.getInstance();

// resources初始化:通过LoadedApk.getResources来创建一个Resources实例

Resources resources = packageInfo.getResources(mainThread);

mResources = resources;// 赋值

//......

mContentResolver = new ApplicationContentResolver(this, mainThread, user);

}

LoadedApk.getResources()

public Resources getResources(ActivityThread mainThread) {

if (mResources == null) {

// ActivityThread.getTopLevelResources()

mResources = mainThread.getTopLevelResources(mResDir/*APK文件位置*/, mSplitResDirs, mOverlayDirs,

mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);

}

return mResources;

}

ActivityThread.getTopLevelResources()

/**

* Creates the top level resources for the given package.

*/

Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,

String[] libDirs, int displayId, Configuration overrideConfiguration,

LoadedApk pkgInfo) {

return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,

displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo());

}

ResourcesManager.getTopLevelResources

/**

* Creates the top level Resources for applications with the given compatibility info.

*

* @param resDir the resource directory.

* @param splitResDirs split resource directories.

* @param overlayDirs the resource overlay directories.

* @param libDirs the shared library resource dirs this app references.

* @param displayId display Id.

* @param overrideConfiguration override configurations.

* @param compatInfo the compatibility info. Must not be null.

*/

Resources getTopLevelResources(String resDir, String[] splitResDirs,

String[] overlayDirs, String[] libDirs, int displayId,

Configuration overrideConfiguration, CompatibilityInfo compatInfo) {

final float scale = compatInfo.applicationScale;

Configuration overrideConfigCopy = (overrideConfiguration != null)

? new Configuration(overrideConfiguration) : null;

ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);

Resources r;

synchronized (this) {

// Resources is app scale dependent.

if (DEBUG) Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);

// Resources是以ResourcesKey为key以弱应用的方式保存在mActiveResources这个Map中

WeakReference wr = mActiveResources.get(key);

r = wr != null ? wr.get() : null;

//if (r != null) Log.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());

if (r != null && r.getAssets().isUpToDate()) {/

// 缓存里面有,并且是最新的

if (DEBUG) Slog.w(TAG, "Returning cached resources " + r + " " + resDir

+ ": appScale=" + r.getCompatibilityInfo().applicationScale

+ " key=" + key + " overrideConfig=" + overrideConfiguration);

return r;

}

}

//if (r != null) {

// Log.w(TAG, "Throwing away out-of-date resources!!!! "

// + r + " " + resDir);

//}

// AssetManager创建

AssetManager assets = new AssetManager();

// resDir can be null if the 'android' package is creating a new Resources object.

// This is fine, since each AssetManager automatically loads the 'android' package

// already.

if (resDir != null) {

if (assets.addAssetPath(resDir) == 0) {

return null;

}

}

if (splitResDirs != null) {

for (String splitResDir : splitResDirs) {

if (assets.addAssetPath(splitResDir) == 0) {

return null;

}

}

}

if (overlayDirs != null) {

for (String idmapPath : overlayDirs) {

assets.addOverlayPath(idmapPath);

}

}

if (libDirs != null) {

for (String libDir : libDirs) {

if (libDir.endsWith(".apk")) {

// Avoid opening files we know do not have resources,

// like code-only .jar files.

if (assets.addAssetPath(libDir) == 0) {

Log.w(TAG, "Asset path '" + libDir +

"' does not exist or contains no resources.");

}

}

}

}

//Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);

DisplayMetrics dm = getDisplayMetricsLocked(displayId);

Configuration config;

final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);

final boolean hasOverrideConfig = key.hasOverrideConfiguration();

if (!isDefaultDisplay || hasOverrideConfig) {

config = new Configuration(getConfiguration());

if (!isDefaultDisplay) {

applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);

}

if (hasOverrideConfig) {

config.updateFrom(key.mOverrideConfiguration);

if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration);

}

} else {

config = getConfiguration();

}

// 创建Resources

r = new Resources(assets, dm, config, compatInfo);

if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "

+ r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);

synchronized (this) {

// 可能其他线程已经创建好了,则直接返回

WeakReference wr = mActiveResources.get(key);

Resources existing = wr != null ? wr.get() : null;

if (existing != null && existing.getAssets().isUpToDate()) {

// Someone else already created the resources while we were

// unlocked; go ahead and use theirs.

r.getAssets().close();

return existing;

}

// XXX need to remove entries when weak references go away

// 把最新的对象保存到缓存中

mActiveResources.put(key, new WeakReference<>(r));

if (DEBUG) Slog.v(TAG, "mActiveResources.size()=" + mActiveResources.size());

return r;

}

}

过程是:先从缓存中取,如果缓存中有且没有过时,则直接返回,否则依次创建AssetManager 和Resources

AssetManager构造函数

/**

* Create a new AssetManager containing only the basic system assets.

* Applications will not generally use this method, instead retrieving the

* appropriate asset manager with {@link Resources#getAssets}. Not for

* use by applications.

* {@hide}

*/

public AssetManager() {

synchronized (this) {

//......

init(false);

// 确保有能够访问系统资源的AssetManager对象

ensureSystemAssets();

}

}

android_util_AssetManager.android_content_AssetManager_init()

static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)

{

if (isSystem) {// false

verifySystemIdmaps();

}

AssetManager* am = new AssetManager();

if (am == NULL) {

jniThrowException(env, "java/lang/OutOfMemoryError", "");

return;

}

am->addDefaultAssets();

ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);

env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast(am));

}

AssetManager.cpp:addDefaultAssets()

bool AssetManager::addDefaultAssets()

{

// root = /system/

const char* root = getenv("ANDROID_ROOT");

LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");

String8 path(root);

// path = /system/framework/framework-res.apk

path.appendPath(kSystemAssets);

return addAssetPath(path, NULL);

}

bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)

{

AutoMutex _l(mLock);

asset_path ap;

String8 realPath(path);

if (kAppZipName) {

// 如果kAppZipName不为NULL(classes.jar),这里这个值是为NULL的

realPath.appendPath(kAppZipName);

}

ap.type = ::getFileType(realPath.string());

if (ap.type == kFileTypeRegular) {// kAppZipName不为NULL

ap.path = realPath;

} else {

// kAppZipName为NULL

ap.path = path;//ap.path指向APK文件

ap.type = ::getFileType(path.string());

if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {

ALOGW("Asset path %s is neither a directory nor file (type=%d).",

path.string(), (int)ap.type);

return false;

}

}

// Skip if we have it already.

for (size_t i=0; i

if (mAssetPaths[i].path == ap.path) {

if (cookie) {

*cookie = static_cast(i+1);

}

return true;

}

}

ALOGV("In %p Asset %s path: %s", this,

ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());

// Check that the path has an AndroidManifest.xml

Asset* manifestAsset = const_cast(this)->openNonAssetInPathLocked(

kAndroidManifest, Asset::ACCESS_BUFFER, ap);

if (manifestAsset == NULL) {

// This asset path does not contain any resources.

delete manifestAsset;

return false;

}

delete manifestAsset;

mAssetPaths.add(ap);

// new paths are always added at the end

if (cookie) {

*cookie = static_cast(mAssetPaths.size());

}

#ifdef __ANDROID__

// Load overlays, if any

asset_path oap;

for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {

mAssetPaths.add(oap);

}

#endif

if (mResources != NULL) {

appendPathToResTable(ap);

}

return true;

}

以上,是AssetManager.java构造函数的第一步:init(false),其主要工作是加载系统资源(framework-res.apk),以供后续应用程序使用。而其第二部:ensureSystemAssets()也是为了创建系统资源使用对象AssetManager

private static void ensureSystemAssets() {

synchronized (sSync) {

if (sSystem == null) {

AssetManager system = new AssetManager(true);

system.makeStringBlocks(null);

sSystem = system;

}

}

}

初始化了AssetManager之后,就可以通过AssetManager.addAssetPath()加载本身资源了.

在AssetManager加载完相关资源后,就可以创建Resources了:

/**

* Creates a new Resources object with CompatibilityInfo.

*

* @param assets Previously created AssetManager.

* @param metrics Current display metrics to consider when

* selecting/computing resource values.

* 设备分辨率相关信息:屏幕分辨率,density,font scaling

* @param config Desired device configuration to consider when

* selecting/computing resource values (optional).

* 该配置信息用来决定使用哪套资源

* @param compatInfo this resource's compatibility info. Must not be null.

* 资源兼容性信息

* @hide

*/

public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,

CompatibilityInfo compatInfo) {

mAssets = assets;

mMetrics.setToDefaults();

if (compatInfo != null) {

mCompatibilityInfo = compatInfo;

}

// 设备相关配置信息更新处理

updateConfiguration(config, metrics);

// 创建字符串资源池

assets.ensureStringBlocks();

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值