相信很多朋友在使用AnimationDrawable做帧动画时,图片过大或者数量过多,很容易就遇到内存溢出问题;

图片过大有很多相关的处理方法,但使用xml配置文件加载数量过多的图片时(40-50张就出现溢出),就比较棘手。

在stackoverflow找到的相关解决方法:http://stackoverflow.com/questions/8692328/causing-outofmemoryerror-in-frame-by-frame-animation-in-android

<-------------------------------------------------------------------------------------------------->

需要jar包:commons-io-1.4.jar

工具类代码如下:

1 import java.io.IOException;  
  2 import java.util.ArrayList;  
  3 import java.util.List;  
  4 import org.apache.commons.io.IOUtils;  
  5 import org.xmlpull.v1.XmlPullParser;  
  6 import org.xmlpull.v1.XmlPullParserException;  
  7 import android.content.Context;  
  8 import android.content.res.XmlResourceParser;  
  9 import android.graphics.BitmapFactory;  
 10 import android.graphics.drawable.AnimationDrawable;  
 11 import android.graphics.drawable.BitmapDrawable;  
 12 import android.graphics.drawable.Drawable;  
 13 import android.os.Handler;  
 14 import android.widget.ImageView;  
 15 
 23 public class MyAnimationDrawable {
 24     public static class MyFrame {  
 25         byte[] bytes;  
 26         int duration;  
 27         Drawable drawable;  
 28         boolean isReady = false;  
 29     }  
 30   
 31     public interface OnDrawableLoadedListener {  
 32         public void onDrawableLoaded(List<MyFrame> myFrames);  
 33     }  
 34   
 35     
 40     public static void animateRawManuallyFromXML(int resourceId,  
 41             final ImageView imageView, final Runnable onStart,  
 42             final Runnable onComplete) {  
 43         loadRaw(resourceId, imageView.getContext(),  
 44                 new OnDrawableLoadedListener() {  
 45                     @Override  
 46                     public void onDrawableLoaded(List<MyFrame> myFrames) {  
 47                         if (onStart != null) {  
 48                             onStart.run();  
 49                         }  
 50                         animateRawManually(myFrames, imageView, onComplete);  
 51                     }  
 52                 });  
 53     }  
 54   
 55     //
 56     private static void loadRaw(final int resourceId, final Context context,  
 57             final OnDrawableLoadedListener onDrawableLoadedListener) {  
 58         loadFromXml(resourceId, context, onDrawableLoadedListener);  
 59     }  
 60   
 61     //
 62     private static void loadFromXml(final int resourceId,  
 63             final Context context,  
 64             final OnDrawableLoadedListener onDrawableLoadedListener) {  
 65         new Thread(new Runnable() {  
 66             @Override  
 67             public void run() {  
 68                 final ArrayList<MyFrame> myFrames = new ArrayList<MyFrame>();  
 69   
 70                 XmlResourceParser parser = context.getResources().getXml(  
 71                         resourceId);  
 72   
 73                 try {  
 74                     int eventType = parser.getEventType();  
 75                     while (eventType != XmlPullParser.END_DOCUMENT) {  
 76                         if (eventType == XmlPullParser.START_DOCUMENT) {  
 77   
 78                         } else if (eventType == XmlPullParser.START_TAG) {  
 79   
 80                             if (parser.getName().equals("item")) {  
 81                                 byte[] bytes = null;  
 82                                 int duration = 1000;  
 83   
 84                                 for (int i = 0; i < parser.getAttributeCount(); i++) {  
 85                                     if (parser.getAttributeName(i).equals(  
 86                                             "drawable")) {  
 87                                         int resId = Integer.parseInt(parser  
 88                                                 .getAttributeValue(i)  
 89                                                 .substring(1));  
 90                                         bytes = IOUtils.toByteArray(context  
 91                                                 .getResources()  
 92                                                 .openRawResource(resId));  
 93                                     } else if (parser.getAttributeName(i)  
 94                                             .equals("duration")) {  
 95                                         duration = parser.getAttributeIntValue(  
 96                                                 i, 1000);  
 97                                     }  
 98                                 }  
 99   
100                                 MyFrame myFrame = new MyFrame();  
101                                 myFrame.bytes = bytes;  
102                                 myFrame.duration = duration;  
103                                 myFrames.add(myFrame);  
104                             }  
105   
106                         } else if (eventType == XmlPullParser.END_TAG) {  
107   
108                         } else if (eventType == XmlPullParser.TEXT) {  
109   
110                         }  
111   
112                         eventType = parser.next();  
113                     }  
114                 } catch (IOException e) {  
115                     e.printStackTrace();  
116                 } catch (XmlPullParserException e2) {  
117                     // TODO: handle exception  
118                     e2.printStackTrace();  
119                 }  
120   
121                 // Run on UI Thread  
122                 new Handler(context.getMainLooper()).post(new Runnable() {  
123                     @Override  
124                     public void run() {  
125                         if (onDrawableLoadedListener != null) {  
126                             onDrawableLoadedListener.onDrawableLoaded(myFrames);  
127                         }  
128                     }  
129                 });  
130             }  
131         }).run();  
132     }  
133   
134     //
135     private static void animateRawManually(List<MyFrame> myFrames,  
136             ImageView imageView, Runnable onComplete) {  
137         animateRawManually(myFrames, imageView, onComplete, 0);  
138     }  
139   
140     //
141     private static void animateRawManually(final List<MyFrame> myFrames,  
142             final ImageView imageView, final Runnable onComplete,  
143             final int frameNumber) {  
144         final MyFrame thisFrame = myFrames.get(frameNumber);  
145   
146         if (frameNumber == 0) {  
147             thisFrame.drawable = new BitmapDrawable(imageView.getContext()  
148                     .getResources(), BitmapFactory.decodeByteArray(  
149                     thisFrame.bytes, 0, thisFrame.bytes.length));  
150         } else {  
151             MyFrame previousFrame = myFrames.get(frameNumber - 1);  
152             ((BitmapDrawable) previousFrame.drawable).getBitmap().recycle();  
153             previousFrame.drawable = null;  
154             previousFrame.isReady = false;  
155         }  
156   
157         imageView.setImageDrawable(thisFrame.drawable);  
158         new Handler().postDelayed(new Runnable() {  
159             @Override  
160             public void run() {  
161                 // Make sure ImageView hasn't been changed to a different Image  
162                 // in this time  
163                 if (imageView.getDrawable() == thisFrame.drawable) {  
164                     if (frameNumber + 1 < myFrames.size()) {  
165                         MyFrame nextFrame = myFrames.get(frameNumber + 1);  
166   
167                         if (nextFrame.isReady) {  
168                             // Animate next frame  
169                             animateRawManually(myFrames, imageView, onComplete,  
170                                     frameNumber + 1);  
171                         } else {  
172                             nextFrame.isReady = true;  
173                         }  
174                     } else {  
175                         if (onComplete != null) {  
176                             onComplete.run();  
177                         }  
178                     }  
179                 }  
180             }  
181         }, thisFrame.duration);  
182   
183         // Load next frame  
184         if (frameNumber + 1 < myFrames.size()) {  
185             new Thread(new Runnable() {  
186                 @Override  
187                 public void run() {  
188                     MyFrame nextFrame = myFrames.get(frameNumber + 1);  
189                     nextFrame.drawable = new BitmapDrawable(imageView  
190                             .getContext().getResources(),  
191                             BitmapFactory.decodeByteArray(nextFrame.bytes, 0,  
192                                     nextFrame.bytes.length));  
193                     if (nextFrame.isReady) {  
194                         // Animate next frame  
195                         animateRawManually(myFrames, imageView, onComplete,  
196                                 frameNumber + 1);  
197                     } else {  
198                         nextFrame.isReady = true;  
199                     }  
200   
201                 }  
202             }).run();  
203         }  
204     }  
205   
206     //带时间的方法 
211     public static void animateManuallyFromRawResource(  
212             int animationDrawableResourceId, ImageView imageView,  
213             Runnable onStart, Runnable onComplete, int duration) throws IOException,  
214             XmlPullParserException {  
215         AnimationDrawable animationDrawable = new AnimationDrawable();  
216   
217         XmlResourceParser parser = imageView.getContext().getResources()  
218                 .getXml(animationDrawableResourceId);  
219   
220         int eventType = parser.getEventType();  
221         while (eventType != XmlPullParser.END_DOCUMENT) {  
222             if (eventType == XmlPullParser.START_DOCUMENT) {  
223   
224             } else if (eventType == XmlPullParser.START_TAG) {  
225   
226                 if (parser.getName().equals("item")) {  
227                     Drawable drawable = null;  
228   
229                     for (int i = 0; i < parser.getAttributeCount(); i++) {  
230                         if (parser.getAttributeName(i).equals("drawable")) {  
231                             int resId = Integer.parseInt(parser  
232                                     .getAttributeValue(i).substring(1));  
233                             byte[] bytes = IOUtils.toByteArray(imageView  
234                                     .getContext().getResources()  
235                                     .openRawResource(resId));//IOUtils.readBytes  
236                             drawable = new BitmapDrawable(imageView  
237                                     .getContext().getResources(),  
238                                     BitmapFactory.decodeByteArray(bytes, 0,  
239                                             bytes.length));  
240                         } else if (parser.getAttributeName(i)  
241                                 .equals("duration")) {  
242                             duration = parser.getAttributeIntValue(i, 66);  
243                         }  
244                     }  
245   
246                     animationDrawable.addFrame(drawable, duration);  
247                 }  
248   
249             } else if (eventType == XmlPullParser.END_TAG) {  
250   
251             } else if (eventType == XmlPullParser.TEXT) {  
252   
253             }  
254   
255             eventType = parser.next();  
256         }  
257   
258         if (onStart != null) {  
259             onStart.run();  
260         }  
261         animateDrawableManually(animationDrawable, imageView, onComplete, 0);  
262     }  
263   
264     private static void animateDrawableManually(  
265             final AnimationDrawable animationDrawable,  
266             final ImageView imageView, final Runnable onComplete,  
267             final int frameNumber) {  
268         final Drawable frame = animationDrawable.getFrame(frameNumber);  
269         imageView.setImageDrawable(frame);  
270         new Handler().postDelayed(new Runnable() {  
271             @Override  
272             public void run() {  
273                 // Make sure ImageView hasn't been changed to a different Image  
274                 // in this time  
275                 if (imageView.getDrawable() == frame) {  
276                     if (frameNumber + 1 < animationDrawable.getNumberOfFrames()) {  
277                         // Animate next frame  
278                         animateDrawableManually(animationDrawable, imageView,  
279                                 onComplete, frameNumber + 1);  
280                     } else {  
281                         // Animation complete  
282                         if (onComplete != null) {  
283                             onComplete.run();  
284                         }  
285                     }  
286                 }  
287             }  
288         }, animationDrawable.getDuration(frameNumber));  
289     }  
290 }

调用方法如下:(帧动画的使用这里不说了,比较容易实现)

参数:anm_image_view-->自定义的xml文件;  anm_image_view-->展示的ImageView控件;
1 MyAnimationDrawable.animateRawManuallyFromXML(R.anim.welcome_anim,
 2                 anm_image_view, new Runnable() {
 3 
 4                     @Override
 5                     public void run() {
 6                         // TODO onStart
 7                         // 动画开始时回调
 9                     }
10                 }, new Runnable() {
11 
12                     @Override
13                     public void run() {
14                         // TODO onComplete
15                         // 动画结束时回调
18                     }
19                 });
25     }