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