android 系统资源的加载和获取

时间:2022-01-14 04:32:26

文章出处:http://blog.csdn.net/shift_wwx


之前的博文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中的资源分配、资源文件的利用,并在这里记录:

android资源文件之:shape详解