文章出处: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路径。
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实现了装载。
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中的资源分配、资源文件的利用,并在这里记录: