文章出处:https://blog.csdn.net/shift_wwx/article/details/39502463
之前的博文android资源访问机制中介绍了android中resources的访问机制,这一篇主要是介绍resources的加载,以及获取。
先来看一下ZygoteInit.java中main函数:
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
if(!SystemProperties.getBoolean("config.enable_quickboot", false)) {
preload();
}
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gc();
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
if (argv[1].equals("start-system-server")) {
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
其中preload():
static void preload() {
preloadClasses();
preloadResources();
preloadOpenGL();
}
这里就可以看出,系统资源是在zygote进程启动的时候被加载的,而且资源加载是在startSystemServer();之前。这样就实现了其他应用进程共享系统资源的目标。
private static void preloadResources() {
final VMRuntime runtime = VMRuntime.getRuntime();
Debug.startAllocCounting();
try {
System.gc();
runtime.runFinalizationSync();
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
Log.i(TAG, "Preloading resources...");
long startTime = SystemClock.uptimeMillis();
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(runtime, ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resources in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
startTime = SystemClock.uptimeMillis();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(runtime, ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resources in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
}
mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, "Failure preloading resources", e);
} finally {
Debug.stopAllocCounting();
}
}
1、Resources.getSystem()
public static Resources getSystem() {
synchronized (sSync) {
Resources ret = mSystem;
if (ret == null) {
ret = new Resources();
mSystem = ret;
}
return ret;
}
}
这里mSystem 是static的,我感觉就是单例,其中ret = new Resources();
private Resources() {
mAssets = AssetManager.getSystem();
// NOTE: Intentionally leaving this uninitialized (all values set
// to zero), so that anyone who tries to do something that requires
// metrics will get a very wrong value.
mConfiguration.setToDefaults();
mMetrics.setToDefaults();
updateConfiguration(null, null);
mAssets.ensureStringBlocks();
}
其中:
public static AssetManager getSystem() {
ensureSystemAssets();
return sSystem;
}
private static void ensureSystemAssets() {
synchronized (sSync) {
if (sSystem == null) {
AssetManager system = new AssetManager(true);
system.makeStringBlocks(false);
sSystem = system;
}
}
}
AssetManager的构造函数就跟之前context获取Resources是一样的了。会调用native的addDefaultAssets(),然后添加framework-res.apk路径。2、preloadDrawables
code中:
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(runtime, ar);
ar.recycle();
需要加载的是preload_drawables中的所有drawable:
<array name="preloaded_drawables">
<item>@drawable/toast_frame</item>
<item>@drawable/btn_check_on_pressed_holo_light</item>
<item>@drawable/btn_check_on_pressed_holo_dark</item>
<item>@drawable/btn_check_on_holo_light</item>
<item>@drawable/btn_check_on_holo_dark</item>
private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
int N = ar.length();
for (int i=0; i<N; i++) {
if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
if (false) {
Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
}
System.gc();
runtime.runFinalizationSync();
Debug.resetGlobalAllocSize();
}
int id = ar.getResourceId(i, 0);
if (false) {
Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
}
if (id != 0) {
if (mResources.getDrawable(id) == null) {
throw new IllegalArgumentException(
"Unable to find preloaded drawable resource #0x"
+ Integer.toHexString(id)
+ " (" + ar.getString(i) + ")");
}
}
}
return N;
}
通过id传入到函数getDrawable(id):
public Drawable getDrawable(int id) throws NotFoundException {
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
if (value == null) {
value = new TypedValue();
} else {
mTmpValue = null;
}
getValue(id, value, true);
}
Drawable res = loadDrawable(value, id);
synchronized (mAccessLock) {
if (mTmpValue == null) {
mTmpValue = value;
}
}
return res;
}
其中loadDrawable实现了装载。3、preloadColorStateLists
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(runtime, ar);
需要加载preloaded_color_state_lists:
<array name="preloaded_color_state_lists">
<item>@color/primary_text_dark</item>
<item>@color/primary_text_dark_disable_only</item>
<item>@color/primary_text_dark_nodisable</item>
<item>@color/primary_text_disable_only_holo_dark</item>
private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
int N = ar.length();
for (int i=0; i<N; i++) {
if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
if (false) {
Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
}
System.gc();
runtime.runFinalizationSync();
Debug.resetGlobalAllocSize();
}
int id = ar.getResourceId(i, 0);
if (false) {
Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
}
if (id != 0) {
if (mResources.getColorStateList(id) == null) {
throw new IllegalArgumentException(
"Unable to find preloaded color resource #0x"
+ Integer.toHexString(id)
+ " (" + ar.getString(i) + ")");
}
}
}
return N;
}
同样是通过id传入到函数getColorStateList(id):
public ColorStateList getColorStateList(int id) throws NotFoundException {
TypedValue value;
synchronized (mAccessLock) {
value = mTmpValue;
if (value == null) {
value = new TypedValue();
} else {
mTmpValue = null;
}
getValue(id, value, true);
}
ColorStateList res = loadColorStateList(value, id);
synchronized (mAccessLock) {
if (mTmpValue == null) {
mTmpValue = value;
}
}
return res;
}
其中loadColorStateList实现了装载。
4、startPreloading 和 finishPreloading
在startPreloading的时候mPreloading会被置true,在finishPreloading的时候将mPreloading置为false
这个mPreloading在loadDrawable等地方起到很关键的作用。
例如loadDrawable:
if (cs != null) {
if (mPreloading) {
final int changingConfigs = cs.getChangingConfigurations();
if (isColorDrawable) {
if (verifyPreloadConfig(changingConfigs, 0, value.resourceId,
"drawable")) {
sPreloadedColorDrawables.put(key, cs);
}
} else {
if (verifyPreloadConfig(changingConfigs,
LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
if ((changingConfigs&LAYOUT_DIR_CONFIG) == 0) {
// If this resource does not vary based on layout direction,
// we can put it in all of the preload maps.
sPreloadedDrawables[0].put(key, cs);
sPreloadedDrawables[1].put(key, cs);
} else {
// Otherwise, only in the layout dir we loaded it for.
final LongSparseArray<Drawable.ConstantState> preloads
= sPreloadedDrawables[mConfiguration.getLayoutDirection()];
preloads.put(key, cs);
}
}
}
} else {
synchronized (mAccessLock) {
//Log.i(TAG, "Saving cached drawable @ #" +
// Integer.toHexString(key.intValue())
// + " in " + this + ": " + cs);
if (isColorDrawable) {
mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
} else {
mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
}
}
}
}
会将drawable存放到不同的地方。这样也可以区别zygote进程和普通进程,因为mPreloading只有在zygote进程才会被修改。结尾:终于小结完了,其中还有很多地方没有细细注释,还是需要实践中掌握。
至于Resources的详解,我想以后也需要多小结的,详细的说说Resources中的资源分配、资源文件的利用,并在这里记录: