Android 使用帧动画内存溢出解决方案

最近在项目遇到的动画效果不好实现,就让UI切成图,采用帧动画实现效果,但是在使用animation-list时,图片也就11张,每张图片大概560k左右,结果内存溢出,崩溃 了,自己用了三张都崩溃;拿代码说;

1.anin_searh.xml

<?xml version="1.0" encoding="utf-8"?>                                

2.使用帧动画

search_scale_iv.setBackgroundResource(R.drawable.anim_search);     AnimationDrawable drawable = (AnimationDrawable) search_scale_iv.getBackground();     drawable.start(); 

结果setBackgroundResource出现内存溢出,这个方法其实获取drawable时候,会消耗很多内存,很容易内存溢出,崩溃。

3.解决方法:在网上找了个类,处理,结果我使用11张560k大小图片,没有内存溢出;

import android.content.Context; import android.content.res.XmlResourceParser; import android.graphics.BitmapFactory; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.widget.ImageView;  import org.apache.commons.io.IOUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException;  import java.io.IOException; import java.util.ArrayList; import java.util.List;  /****  * 此工具类源于stack over flow  * 原文链接:http://stackoverflow.com/questions/8692328/causing-outofmemoryerror-in-frame-by-frame-animation-in-android  * 主要使用了BitmapFactory.decodeByteArray方法通过底层C来绘制图片,有效防止OOM  * 使用了第三方类库:org.apache.commons.io.IOUtils,将Inputstream转为byte字节数组  * *******/ public class MyAnimationDrawable {    public static class MyFrame {     byte[] bytes;     int duration;     Drawable drawable;     boolean isReady = false;   }    public interface OnDrawableLoadedListener {     public void onDrawableLoaded(List myFrames);   }    // 1   /***    * 性能更优    * 在animation-list中设置时间    * **/   public static void animateRawManuallyFromXML(int resourceId,                          final ImageView imageView, final Runnable onStart,                          final Runnable onComplete) {     loadRaw(resourceId, imageView.getContext(),         new OnDrawableLoadedListener() {           @Override           public void onDrawableLoaded(List myFrames) {             if (onStart != null) {               onStart.run();             }             animateRawManually(myFrames, imageView, onComplete);           }         });   }    // 2   private static void loadRaw(final int resourceId, final Context context,                 final OnDrawableLoadedListener onDrawableLoadedListener) {     loadFromXml(resourceId, context, onDrawableLoadedListener);   }    // 3   private static void loadFromXml(final int resourceId,                   final Context context,                   final OnDrawableLoadedListener onDrawableLoadedListener) {     new Thread(new Runnable() {       @Override       public void run() {         final ArrayList myFrames = new ArrayList();          XmlResourceParser parser = context.getResources().getXml(             resourceId);          try {           int eventType = parser.getEventType();           while (eventType != XmlPullParser.END_DOCUMENT) {             if (eventType == XmlPullParser.START_DOCUMENT) {              } else if (eventType == XmlPullParser.START_TAG) {                if (parser.getName().equals("item")) {                 byte[] bytes = null;                 int duration = 1000;                  for (int i = 0; i < parser.getAttributeCount(); i++) {                   if (parser.getAttributeName(i).equals(                       "drawable")) {                     int resId = Integer.parseInt(parser                         .getAttributeValue(i)                         .substring(1));                     bytes = IOUtils.toByteArray(context                         .getResources()                         .openRawResource(resId));                   } else if (parser.getAttributeName(i)                       .equals("duration")) {                     duration = parser.getAttributeIntValue(                         i, 1000);                   }                 }                  MyFrame myFrame = new MyFrame();                 myFrame.bytes = bytes;                 myFrame.duration = duration;                 myFrames.add(myFrame);               }              } else if (eventType == XmlPullParser.END_TAG) {              } else if (eventType == XmlPullParser.TEXT) {              }              eventType = parser.next();           }         } catch (IOException e) {           e.printStackTrace();         } catch (XmlPullParserException e2) {           // TODO: handle exception           e2.printStackTrace();         }          // Run on UI Thread         new Handler(context.getMainLooper()).post(new Runnable() {           @Override           public void run() {             if (onDrawableLoadedListener != null) {               onDrawableLoadedListener.onDrawableLoaded(myFrames);             }           }         });       }     }).run();   }    // 4   private static void animateRawManually(List myFrames,                       ImageView imageView, Runnable onComplete) {     animateRawManually(myFrames, imageView, onComplete, 0);   }    // 5   private static void animateRawManually(final List myFrames,                       final ImageView imageView, final Runnable onComplete,                       final int frameNumber) {     final MyFrame thisFrame = myFrames.get(frameNumber);      if (frameNumber == 0) {       thisFrame.drawable = new BitmapDrawable(imageView.getContext()           .getResources(), BitmapFactory.decodeByteArray(           thisFrame.bytes, 0, thisFrame.bytes.length));     } else {       MyFrame previousFrame = myFrames.get(frameNumber - 1);       ((BitmapDrawable) previousFrame.drawable).getBitmap().recycle();       previousFrame.drawable = null;       previousFrame.isReady = false;     }      imageView.setImageDrawable(thisFrame.drawable);     new Handler().postDelayed(new Runnable() {       @Override       public void run() {         // Make sure ImageView hasn't been changed to a different Image         // in this time         if (imageView.getDrawable() == thisFrame.drawable) {           if (frameNumber + 1 < myFrames.size()) {             MyFrame nextFrame = myFrames.get(frameNumber + 1);              if (nextFrame.isReady) {               // Animate next frame               animateRawManually(myFrames, imageView, onComplete,                   frameNumber + 1);             } else {               nextFrame.isReady = true;             }           } else {             if (onComplete != null) {               onComplete.run();             }           }         }       }     }, thisFrame.duration);      // Load next frame     if (frameNumber + 1 < myFrames.size()) {       new Thread(new Runnable() {         @Override         public void run() {           MyFrame nextFrame = myFrames.get(frameNumber + 1);           nextFrame.drawable = new BitmapDrawable(imageView               .getContext().getResources(),               BitmapFactory.decodeByteArray(nextFrame.bytes, 0,                   nextFrame.bytes.length));           if (nextFrame.isReady) {             // Animate next frame             animateRawManually(myFrames, imageView, onComplete,                 frameNumber + 1);           } else {             nextFrame.isReady = true;           }          }       }).run();     }   }    //第二种方法   /***    * 代码中控制时间,但不精确    * duration = 1000;    * ****/   public static void animateManuallyFromRawResource(       int animationDrawableResourceId, ImageView imageView,       Runnable onStart, Runnable onComplete, int duration) throws IOException,       XmlPullParserException {     AnimationDrawable animationDrawable = new AnimationDrawable();      XmlResourceParser parser = imageView.getContext().getResources()         .getXml(animationDrawableResourceId);      int eventType = parser.getEventType();     while (eventType != XmlPullParser.END_DOCUMENT) {       if (eventType == XmlPullParser.START_DOCUMENT) {        } else if (eventType == XmlPullParser.START_TAG) {          if (parser.getName().equals("item")) {           Drawable drawable = null;            for (int i = 0; i < parser.getAttributeCount(); i++) {             if (parser.getAttributeName(i).equals("drawable")) {               int resId = Integer.parseInt(parser                   .getAttributeValue(i).substring(1));               byte[] bytes = IOUtils.toByteArray(imageView                   .getContext().getResources()                   .openRawResource(resId));//IOUtils.readBytes               drawable = new BitmapDrawable(imageView                   .getContext().getResources(),                   BitmapFactory.decodeByteArray(bytes, 0,                       bytes.length));             } else if (parser.getAttributeName(i)                 .equals("duration")) {               duration = parser.getAttributeIntValue(i, 66);             }           }            animationDrawable.addFrame(drawable, duration);         }        } else if (eventType == XmlPullParser.END_TAG) {        } else if (eventType == XmlPullParser.TEXT) {        }        eventType = parser.next();     }      if (onStart != null) {       onStart.run();     }     animateDrawableManually(animationDrawable, imageView, onComplete, 0);   }    private static void animateDrawableManually(       final AnimationDrawable animationDrawable,       final ImageView imageView, final Runnable onComplete,       final int frameNumber) {     final Drawable frame = animationDrawable.getFrame(frameNumber);     imageView.setImageDrawable(frame);     new Handler().postDelayed(new Runnable() {       @Override       public void run() {         // Make sure ImageView hasn't been changed to a different Image         // in this time         if (imageView.getDrawable() == frame) {           if (frameNumber + 1 < animationDrawable.getNumberOfFrames()) {             // Animate next frame             animateDrawableManually(animationDrawable, imageView,                 onComplete, frameNumber + 1);           } else {             // Animation complete             if (onComplete != null) {               onComplete.run();             }           }         }       }     }, animationDrawable.getDuration(frameNumber));   }  } 

这里需要导入jar,

import org.apache.commons.io.IOUtils;

4.然后通过上述类,来调用自己的动画xml,

MyAnimationDrawable.animateRawManuallyFromXML(R.drawable.anim_search,             search_scale_iv, new Runnable() {                @Override               public void run() {                 // TODO onStart                 // 动画开始时回调                 log.d("","start");                                }             }, new Runnable() {                @Override               public void run() {                 // TODO onComplete                 // 动画结束时回调                 log.d("","end");                                }             }); 

这样在使用帧动画时,可以有效的适度防止内存溢出,谁还有什么办法,欢迎交流!

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

更多相关文章

  1. Tween动画
  2. 查看android进程信息
  3. Android(安卓)APP优化—Android程序员必须掌握
  4. Android(安卓)Frame Animation 帧动画不播放问题。
  5. Android解码/显示/播放Gif图片动画
  6. Android属性动画---Property Animation(四)
  7. Android(安卓)Training Caching Bitmaps 翻译
  8. 内存泄漏—Android(安卓)Studio 3.0 Profiler入门
  9. 动画效果编程基础

随机推荐

  1. 【网络爬虫】【java】微博爬虫(四):数据处理
  2. 正文获取摘要 去除html标记
  3. a标签的link、visited、hover、active的
  4. Html页面Js调用android本地相机和图片
  5. 让Vs2010支持 Css3+HTML5
  6. 高手请进,90分相送!
  7. 如何在不制作正确的浮动包装的情况下填充
  8. 为什么我不用Javascript和Javascript HTM
  9. JS动态生成Table
  10. 如何在窗体上布局文本和输入以适应特定的