安卓应用的运行内存不像PC那样富有,虽然java本身也加入了GC垃圾回收机制,但是对内存的优化还是有一定必要的,尤其在一些低配手机上,内存小的问题更突出,OOM也更常见。
----------------------------------------------------------------------------------
一个安卓应用项目中,res目录下图片资源占了一大部分,虽然系统对Resource增加了缓存机制,但是仍然还是可以进行一些优化的,这篇文章主要说一下app中res下图片资源的加载过程中可能进行的一些简单优化。
----------------------------------------------------------------------------------
安卓控件设置背景,图片资源时一般会调用View#setBackgroundResource(int)和ImageView#setImageResource(int)等方法,
这些方法最终都会通过调用 Resources#getDrawable(int) ,Resources#loadDrawable(TypedValue, int)来加载Drawable资源,而该方法加载图片,颜色,xml资源时,是分开处理的,系统源码如下所示:
1.Drawable#loadDrawable
/*package*/ Drawable loadDrawable(TypedValue value, int id) throws NotFoundException { if (TRACE_FOR_PRELOAD) { // Log only framework resources if ((id >>> 24) == 0x1) { final String name = getResourceName(id); if (name != null) android.util.Log.d("PreloadDrawable", name); } } boolean isColorDrawable = false; if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { isColorDrawable = true; } final long key = isColorDrawable ? value.data : (((long) value.assetCookie) << 32) | value.data; Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key); if (dr != null) { return dr; } Drawable.ConstantState cs; if (isColorDrawable) { cs = sPreloadedColorDrawables.get(key); } else { cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key); } if (cs != null) { dr = cs.newDrawable(this); } else { if (isColorDrawable) { dr = new ColorDrawable(value.data); } if (dr == null) { if (value.string == null) { throw new NotFoundException( "Resource is not a Drawable (color or path): " + value); } String file = value.string.toString(); if (TRACE_FOR_MISS_PRELOAD) { // Log only framework resources if ((id >>> 24) == 0x1) { final String name = getResourceName(id); if (name != null) android.util.Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id) + ": " + name + " at " + file); } } if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file); if (file.endsWith(".xml")) { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); try { XmlResourceParser rp = loadXmlResourceParser( file, id, value.assetCookie, "drawable"); dr = Drawable.createFromXml(this, rp); rp.close(); } catch (Exception e) { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); NotFoundException rnf = new NotFoundException( "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); rnf.initCause(e); throw rnf; } Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } else { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); try { InputStream is = mAssets.openNonAsset( value.assetCookie, file, AssetManager.ACCESS_STREAMING); // System.out.println("Opened file " + file + ": " + is); dr = Drawable.createFromResourceStream(this, value, is, file, null); is.close(); // System.out.println("Created stream: " + dr); } catch (Exception e) { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); NotFoundException rnf = new NotFoundException( "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); rnf.initCause(e); throw rnf; } Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } } } if (dr != null) { dr.setChangingConfigurations(value.changingConfigurations); cs = dr.getConstantState(); 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)); } } } } } return dr; }
其中,如果是色值,则
if (isColorDrawable) { dr = new ColorDrawable(value.data); }
如果是xml资源,比如按钮背景selector,则最终调用Drawable#createFromXml(Resources, XmlResourceParser)来创建Drawable
if (file.endsWith(".xml")) { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); try { XmlResourceParser rp = loadXmlResourceParser( file, id, value.assetCookie, "drawable"); dr = Drawable.createFromXml(this, rp); rp.close(); } catch (Exception e) { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); NotFoundException rnf = new NotFoundException( "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); rnf.initCause(e); throw rnf; } Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); }
如果是图片资源(jpg,png),则最终调用Drawable#createFromResourceStream(Resources, TypedValue, InputStream, String, Option)来创建Drawable
if (file.endsWith(".xml")) { ... ... } else { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); try { InputStream is = mAssets.openNonAsset( value.assetCookie, file, AssetManager.ACCESS_STREAMING); // System.out.println("Opened file " + file + ": " + is); dr = Drawable.createFromResourceStream(this, value, is, file, null); is.close(); // System.out.println("Created stream: " + dr); } catch (Exception e) { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); NotFoundException rnf = new NotFoundException( "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); rnf.initCause(e); throw rnf; } Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); }
到了这里,着重分析一下,我们也是主要从加载图片这一块来看一下优化思路。
接下来看一下Drawable#createFromResourceStream(Resources, TypedValue, InputStream, String, Option)方法
2.Drawable#createFromResourceStream(Resources, TypedValue, InputStream, String, Option)
/** * Create a drawable from an inputstream, using the given resources and * value to determine density information. */ public static Drawable createFromResourceStream(Resources res, TypedValue value, InputStream is, String srcName, BitmapFactory.Options opt
Android内存优化-图片资源
最新推荐文章于 2022-05-31 22:37:37 发布