android oom 代码注意

来源:互联网 发布:淘宝店铺海报制作 编辑:程序博客网 时间:2024/06/16 14:41


    View.java
     
    1. /**
    2.
    3.      * Simple constructor to use when creating a view from code.
    4.
    5.      *
    6.
    7.      * @param context The Context the view is running in, through which it can
    8.
    9.      *        access the current theme, resources, etc.
    10.
    11.      */
    12.
    13.     public View(Context context) {
    14.
    15.         mContext = context;
    16.
    17.         mResources = context != null ? context.getResources() : null;
    18.
    19.         mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
    20.
    21.         // Used for debug only
    22.
    23.         //++sInstanceCount;
    24.
    25.         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    26.
    27. }

    View 保存了对context的引用,mContext = context;
    1.我们知道结构其实和DOM差不多,都会保存其父容器、子容器的引用,因而context的使用需要注意,不要使用静态的子View。
    2.来看View中的setBackgroundDrawable方法
    View.java
     
    1. /**
    2.
    3.      * Set the background to a given Drawable, or remove the background. If the
    4.
    5.      * background has padding, this View's padding is set to the background's
    6.
    7.      * padding. However, when a background is removed, this View's padding isn't
    8.
    9.      * touched. If setting the padding is desired, please use
    10.
    11.      * {@link #setPadding(int, int, int, int)}.
    12.
    13.      *
    14.
    15.      * @param d The Drawable to use as the background, or null to remove the
    16.
    17.      *        background
    18.
    19.      */
    20.
    21.     public void setBackgroundDrawable(Drawable d) {
    22.
    23.         boolean requestLayout = false;
    24.
    25.  
    26.
    27.         mBackgroundResource = 0;
    28.
    29.  
    30.
    31.         /*
    32.
    33.          * Regardless of whether we're setting a new background or not, we want
    34.
    35.          * to clear the previous drawable.
    36.
    37.          */
    38.
    39.         if (mBGDrawable != null) {
    40.
    41.             mBGDrawable.setCallback(null);
    42.
    43.             unscheduleDrawable(mBGDrawable);
    44.
    45.         }
    46.
    47.  
    48.
    49.         if (d != null) {
    50.
    51.             Rect padding = sThreadLocal.get();
    52.
    53.             if (padding == null) {
    54.
    55.                 padding = new Rect();
    56.
    57.                 sThreadLocal.set(padding);
    58.
    59.             }
    60.
    61.             if (d.getPadding(padding)) {
    62.
    63.                 setPadding(padding.left, padding.top, padding.right, padding.bottom);
    64.
    65.             }
    66.
    67.  
    68.
    69.             // Compare the minimum sizes of the old Drawable and the new.  If there isn't an old or
    70.
    71.             // if it has a different minimum size, we should layout again
    72.
    73.             if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() ||
    74.
    75.                     mBGDrawable.getMinimumWidth() != d.getMinimumWidth()) {
    76.
    77.                 requestLayout = true;
    78.
    79.             }
    80.
    81.  
    82.
    83.             d.setCallback(this);
    84.
    85.             if (d.isStateful()) {
    86.
    87.                 d.setState(getDrawableState());
    88.
    89.             }
    90.
    91.             d.setVisible(getVisibility() == VISIBLE, false);
    92.
    93.             mBGDrawable = d;
    94.
    95.  
    96.
    97.             if ((mPrivateFlags & SKIP_DRAW) != 0) {
    98.
    99.                 mPrivateFlags &= ~SKIP_DRAW;
    100.
    101.                 mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
    102.
    103.                 requestLayout = true;
    104.
    105.             }
    106.
    107.         } else {
    108.
    109.             /* Remove the background */
    110.
    111.             mBGDrawable = null;
    112.
    113.  
    114.
    115.             if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) {
    116.
    117.                 /*
    118.
    119.                  * This view ONLY drew the background before and we're removing
    120.
    121.                  * the background, so now it won't draw anything
    122.
    123.                  * (hence we SKIP_DRAW)
    124.
    125.                  */
    126.
    127.                 mPrivateFlags &= ~ONLY_DRAWS_BACKGROUND;
    128.
    129.                 mPrivateFlags |= SKIP_DRAW;
    130.
    131.             }
    132.
    133.  
    134.
    135.             /*
    136.
    137.              * When the background is set, we try to apply its padding to this
    138.
    139.              * View. When the background is removed, we don't touch this View's
    140.
    141.              * padding. This is noted in the Javadocs. Hence, we don't need to
    142.
    143.              * requestLayout(), the invalidate() below is sufficient.
    144.
    145.              */
    146.
    147.  
    148.
    149.             // The old background's minimum size could have affected this
    150.
    151.             // View's layout, so let's requestLayout
    152.
    153.             requestLayout = true;
    154.
    155.         }
    156.
    157.  
    158.
    159.         computeOpaqueFlags();
    160.
    161.  
    162.
    163.         if (requestLayout) {
    164.
    165.             requestLayout();
    166.
    167.         }
    168.
    169.  
    170.
    171.         mBackgroundSizeChanged = true;
    172.
    173.         invalidate();
    174.
    175.     }
    我们注意到d.setCallback(this);
    即Drawable保存了View的引用,处理了一些回调。因此,Drawable对象使用时需要注意了。不要作为静态对象使用。www.2cto.com
     
    Resource.getDrewable()方法是比较好的,Resource内部使用了一个Drawable.ConstantState的弱引用缓存,提高了效率。
    来看代码:
    Resource.java
     
    1. /*package*/ Drawable loadDrawable(TypedValue value, int id)
    2.
    3.             throws NotFoundException {
    4.
    5.  
    6.
    7.         if (TRACE_FOR_PRELOAD) {
    8.
    9.             // Log only framework resources
    10.
    11.             if ((id >>> 24) == 0x1) {
    12.
    13.                 final String name = getResourceName(id);
    14.
    15.                 if (name != null) android.util.Log.d("PreloadDrawable", name);
    16.
    17.             }
    18.
    19.         }
    20.
    21.  
    22.
    23.         final long key = (((long) value.assetCookie) << 32) | value.data;
    24.
    25.         Drawable dr = getCachedDrawable(key);
    26.
    27.  
    28.
    29.         if (dr != null) {
    30.
    31.             return dr;
    32.
    33.         }
    34.
    35.  
    36.
    37.         Drawable.ConstantState cs = sPreloadedDrawables.get(key);
    38.
    39.         if (cs != null) {
    40.
    41.             dr = cs.newDrawable(this);
    42.
    43.         } else {
    44.
    45.             if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
    46.
    47.                     value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
    48.
    49.                 dr = new ColorDrawable(value.data);
    50.
    51.             }
    52.
    53.  
    54.
    55.             if (dr == null) {
    56.
    57.                 if (value.string == null) {
    58.
    59.                     throw new NotFoundException(
    60.
    61.                             "Resource is not a Drawable (color or path): " + value);
    62.
    63.                 }
    64.
    65.  
    66.
    67.                 String file = value.string.toString();
    68.
    69.  
    70.
    71.                 if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
    72.
    73.                         + value.assetCookie + ": " + file);
    74.
    75.  
    76.
    77.                 if (file.endsWith(".xml")) {
    78.
    79.                     try {
    80.
    81.                         XmlResourceParser rp = loadXmlResourceParser(
    82.
    83.                                 file, id, value.assetCookie, "drawable");
    84.
    85.                         dr = Drawable.createFromXml(this, rp);
    86.
    87.                         rp.close();
    88.
    89.                     } catch (Exception e) {
    90.
    91.                         NotFoundException rnf = new NotFoundException(
    92.
    93.                             "File " + file + " from drawable resource ID #0x"
    94.
    95.                             + Integer.toHexString(id));
    96.
    97.                         rnf.initCause(e);
    98.
    99.                         throw rnf;
    100.
    101.                     }
    102.
    103.  
    104.
    105.                 } else {
    106.
    107.                     try {
    108.
    109.                         InputStream is = mAssets.openNonAsset(
    110.
    111.                                 value.assetCookie, file, AssetManager.ACCESS_STREAMING);
    112.
    113.         //                System.out.println("Opened file " + file + ": " + is);
    114.
    115.                         dr = Drawable.createFromResourceStream(this, value, is,
    116.
    117.                                 file, null);
    118.
    119.                         is.close();
    120.
    121.         //                System.out.println("Created stream: " + dr);
    122.
    123.                     } catch (Exception e) {
    124.
    125.                         NotFoundException rnf = new NotFoundException(
    126.
    127.                             "File " + file + " from drawable resource ID #0x"
    128.
    129.                             + Integer.toHexString(id));
    130.
    131.                         rnf.initCause(e);
    132.
    133.                         throw rnf;
    134.
    135.                     }
    136.
    137.                 }
    138.
    139.             }
    140.
    141.         }
    142.
    143.  
    144.
    145.         if (dr != null) {
    146.
    147.             dr.setChangingConfigurations(value.changingConfigurations);
    148.
    149.             cs = dr.getConstantState();
    150.
    151.             if (cs != null) {
    152.
    153.                 if (mPreloading) {
    154.
    155.                     sPreloadedDrawables.put(key, cs);
    156.
    157.                 } else {
    158.
    159.                     synchronized (mTmpValue) {
    160.
    161.                         //Log.i(TAG, "Saving cached drawable @ #" +
    162.
    163.                         //        Integer.toHexString(key.intValue())
    164.
    165.                         //        + " in " + this + ": " + cs);
    166.
    167.                         mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
    168.
    169.                     }
    170.
    171.                 }
    172.
    173.             }
    174.
    175.         }
    176.
    177.  
    178.
    179.         return dr;
    180.
    181.     }
    使用Drawable一般情况下效率较高,且不易发生内存泄露。
     
    接下来我们来看下BitMap的使用
     
    BitMapFactory.java
     
    1. /**
    2.
    3.      * Decode an input stream into a bitmap. If the input stream is null, or
    4.
    5.      * cannot be used to decode a bitmap, the function returns null.
    6.
    7.      * The stream's position will be where ever it was after the encoded data
    8.
    9.      * was read.
    10.
    11.      *
    12.
    13.      * @param is The input stream that holds the raw data to be decoded into a
    14.
    15.      *           bitmap.
    16.
    17.      * @param outPadding If not null, return the padding rect for the bitmap if
    18.
    19.      *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
    20.
    21.      *                   no bitmap is returned (null) then padding is
    22.
    23.      *                   unchanged.
    24.
    25.      * @param opts null-ok; Options that control downsampling and whether the
    26.
    27.      *             image should be completely decoded, or just is size returned.
    28.
    29.      * @return The decoded bitmap, or null if the image data could not be
    30.
    31.      *         decoded, or, if opts is non-null, if opts requested only the
    32.
    33.      *         size be returned (in opts.outWidth and opts.outHeight)
    34.
    35.      */
    36.
    37.     public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
    38.
    39.         // we don't throw in this case, thus allowing the caller to only check
    40.
    41.         // the cache, and not force the image to be decoded.
    42.
    43.         if (is == null) {
    44.
    45.             return null;
    46.
    47.         }
    48.
    49.  
    50.
    51.         // we need mark/reset to work properly
    52.
    53.  
    54.
    55.         if (!is.markSupported()) {
    56.
    57.             is = new BufferedInputStream(is, 16 * 1024);
    58.
    59.         }
    60.
    61.  
    62.
    63.         // so we can call reset() if a given codec gives up after reading up to
    64.
    65.         // this many bytes. FIXME: need to find out from the codecs what this
    66.
    67.         // value should be.
    68.
    69.         is.mark(1024);
    70.
    71.  
    72.
    73.         Bitmap  bm;
    74.
    75.  
    76.
    77.         if (is instanceof AssetManager.AssetInputStream) {
    78.
    79.             bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
    80.
    81.                     outPadding, opts);
    82.
    83.         } else {
    84.
    85.             // pass some temp storage down to the native code. 1024 is made up,
    86.
    87.             // but should be large enough to avoid too many small calls back
    88.
    89.             // into is.read(...) This number is not related to the value passed
    90.
    91.             // to mark(...) above.
    92.
    93.             byte [] tempStorage = null;
    94.
    95.             if (opts != null)
    96.
    97.                 tempStorage = opts.inTempStorage;
    98.
    99.             if (tempStorage == null)
    100.
    101.                 tempStorage = new byte[16 * 1024];
    102.
    103.             bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
    104.
    105.         }
    106.
    107.  
    108.
    109.         return finishDecode(bm, outPadding, opts);
    110.
    111.     }
    我们每次调用BitMapFactory中的生产bitmap的方法的时候都会new一个bitmap出来,为了避免内存溢出,我们有两种主要的思路:
    1.       使用缓存,避免重复new同一个图片
    2.       销毁bitmap,使用完之后立刻销毁bitmap
    缓存需要自己实现,如果是销毁的话,可以使用Bitmap中的recycle()方法。

    摘自  ZillaPress
原创粉丝点击