2025-05-25

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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *