Context部分
View的構造函數
View.java
- /**
- * Simple constructor to use when creating a view from code.
- *
- * @param context The Context the view is running in, through which it can
- * access the current theme, resources, etc.
- */
- public View(Context context) {
- mContext = context;
- mResources = context != null ? context.getResources() : null;
- mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
- // Used for debug only
- //++sInstanceCount;
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- }
View 保存了對context的引用,mContext = context;
1.我們知道結構其實和DOM差不多,都會保存其父容器、子容器的引用,因而context的使用需要注意,不要使用靜態的子View。
2.來看View中的setBackgroundDrawable方法
View.java
- /**
- * Set the background to a given Drawable, or remove the background. If the
- * background has padding, this View's padding is set to the background's
- * padding. However, when a background is removed, this View's padding isn't
- * touched. If setting the padding is desired, please use
- * {@link #setPadding(int, int, int, int)}.
- *
- * @param d The Drawable to use as the background, or null to remove the
- * background
- */
- public void setBackgroundDrawable(Drawable d) {
- boolean requestLayout = false;
- mBackgroundResource = 0;
- /*
- * Regardless of whether we're setting a new background or not, we want
- * to clear the previous drawable.
- */
- if (mBGDrawable != null) {
- mBGDrawable.setCallback(null);
- unscheduleDrawable(mBGDrawable);
- }
- if (d != null) {
- Rect padding = sThreadLocal.get();
- if (padding == null) {
- padding = new Rect();
- sThreadLocal.set(padding);
- }
- if (d.getPadding(padding)) {
- setPadding(padding.left, padding.top, padding.right, padding.bottom);
- }
- // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
- // if it has a different minimum size, we should layout again
- if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() ||
- mBGDrawable.getMinimumWidth() != d.getMinimumWidth()) {
- requestLayout = true;
- }
- d.setCallback(this);
- if (d.isStateful()) {
- d.setState(getDrawableState());
- }
- d.setVisible(getVisibility() == VISIBLE, false);
- mBGDrawable = d;
- if ((mPrivateFlags & SKIP_DRAW) != 0) {
- mPrivateFlags &= ~SKIP_DRAW;
- mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
- requestLayout = true;
- }
- } else {
- /* Remove the background */
- mBGDrawable = null;
- if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) {
- /*
- * This view ONLY drew the background before and we're removing
- * the background, so now it won't draw anything
- * (hence we SKIP_DRAW)
- */
- mPrivateFlags &= ~ONLY_DRAWS_BACKGROUND;
- mPrivateFlags |= SKIP_DRAW;
- }
- /*
- * When the background is set, we try to apply its padding to this
- * View. When the background is removed, we don't touch this View's
- * padding. This is noted in the Javadocs. Hence, we don't need to
- * requestLayout(), the invalidate() below is sufficient.
- */
- // The old background's minimum size could have affected this
- // View's layout, so let's requestLayout
- requestLayout = true;
- }
- computeOpaqueFlags();
- if (requestLayout) {
- requestLayout();
- }
- mBackgroundSizeChanged = true;
- invalidate();
- }
我們注意到d.setCallback(this);
即Drawable保存了View的引用,處理了一些回調。因此,Drawable對象使用時需要注意了。不要作為靜態對象使用。
Resource.getDrewable()方法是比較好的,Resource內部使用了一個Drawable.ConstantState的弱引用緩存,提高了效率。
來看代碼:
Resource.java
- /*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);
- }
- }
- final long key = (((long) value.assetCookie) << 32) | value.data;
- Drawable dr = getCachedDrawable(key);
- if (dr != null) {
- return dr;
- }
- Drawable.ConstantState cs = sPreloadedDrawables.get(key);
- if (cs != null) {
- dr = cs.newDrawable(this);
- } else {
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
- value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- 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 (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
- + value.assetCookie + ": " + file);
- if (file.endsWith(".xml")) {
- try {
- XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "drawable");
- dr = Drawable.createFromXml(this, rp);
- rp.close();
- } catch (Exception e) {
- NotFoundException rnf = new NotFoundException(
- "File " + file + " from drawable resource ID #0x"
- + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
- } else {
- 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) {
- NotFoundException rnf = new NotFoundException(
- "File " + file + " from drawable resource ID #0x"
- + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
- }
- }
- }
- if (dr != null) {
- dr.setChangingConfigurations(value.changingConfigurations);
- cs = dr.getConstantState();
- if (cs != null) {
- if (mPreloading) {
- sPreloadedDrawables.put(key, cs);
- } else {
- synchronized (mTmpValue) {
- //Log.i(TAG, "Saving cached drawable @ #" +
- // Integer.toHexString(key.intValue())
- // + " in " + this + ": " + cs);
- mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
- }
- }
- }
- }
- return dr;
- }
使用Drawable一般情況下效率較高,且不易發生內存洩露。
接下來我們來看下BitMap的使用
BitMapFactory.java
- /**
- * Decode an input stream into a bitmap. If the input stream is null, or
- * cannot be used to decode a bitmap, the function returns null.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
- // we don't throw in this case, thus allowing the caller to only check
- // the cache, and not force the image to be decoded.
- if (is == null) {
- return null;
- }
- // we need mark/reset to work properly
- if (!is.markSupported()) {
- is = new BufferedInputStream(is, 16 * 1024);
- }
- // so we can call reset() if a given codec gives up after reading up to
- // this many bytes. FIXME: need to find out from the codecs what this
- // value should be.
- is.mark(1024);
- Bitmap bm;
- if (is instanceof AssetManager.AssetInputStream) {
- bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
- outPadding, opts);
- } else {
- // pass some temp storage down to the native code. 1024 is made up,
- // but should be large enough to avoid too many small calls back
- // into is.read(...) This number is not related to the value passed
- // to mark(...) above.
- byte [] tempStorage = null;
- if (opts != null)
- tempStorage = opts.inTempStorage;
- if (tempStorage == null)
- tempStorage = new byte[16 * 1024];
- bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
- }
- return finishDecode(bm, outPadding, opts);
- }
我們每次調用BitMapFactory中的生產bitmap的方法的時候都會new一個bitmap出來,為了避免內存溢出,我們有兩種主要的思路:
1. 使用緩存,避免重復new同一個圖片
2. 銷毀bitmap,使用完之後立刻銷毀bitmap
緩存需要自己實現,如果是銷毀的話,可以使用Bitmap中的recycle()方法。
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11