1. 概述
上节课的插件换肤,我们只是了解了下AssetManager,我们知道资源加载的时候其实最终调用的是 AssetManager的 addAssetPath()方法,那么接下来我们就来看下 Native层的 AssetManager的源码。
如果对于插件换肤相关知识不是很理解的,可以先去看我之前的文章:
插件式换肤示例代码演示
2. AssetManager源码如下
2.1>: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) {
if (DEBUG_REFS) {
mNumRefs = 0;
incRefsLocked(this.hashCode());
}
init(false);
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
ensureSystemAssets();
}
}
2.2>:点击里边的init(false)方法,可以看到,这个方法是一个 native方法,也就是c、c++的方法,这个时候就只能去看 Native层的AssetManager源码,那么接下来我们就去看下Native层的AssetManager源码:
private native final void init(boolean isSystem);
3. Native层的AssetManager源码如下:
3.1>:点击上边的 init(boolean isSystem)方法,会调用下边的 native方法,然后就会调用这个方法的 addDefaultAssets()方法,表示添加默认的资源
// android_content_AssetManager_init:包名 + 方法名
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem){
if (isSystem) {
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<jlong>(am));
}
3.2>:addDefaultAssets()方法如下,可以看到,最终会返回addAssetPath(path, NULL)方法 :
bool AssetManager::addDefaultAssets() {
// 先添加一个路径 ,
// kSystemAssets 就是 framework/framework-res.apk
// 首先会加载系统提供好的资源文件
// 比如可以在布局文件中的ImageView直接添加android:src="@android:mipmap/sym_def_app_icon"
path.appendPath(kSystemAssets);
return addAssetPath(path, NULL);
3.3>:addAssetPath(path, NULL)方法 如下:
bool AssetManager::addAssetPath(const String8& path, int32_t* cookie){
// Check that the path has an AndroidManifest.xml
Asset* manifestAsset = const_cast<AssetManager*>(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<int32_t>(mAssetPaths.size());
}
if (mResources != NULL) {
appendPathToResTable(ap);
}
return true;
}