灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2139回复:0

android OOM的那些事

楼主#
更多 发布于:2012-09-06 13:48


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.atcpu.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

喜欢0 评分0
游客

返回顶部