首页 > 系统 > Android > 正文

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

2019-12-12 04:12:51
字体:
来源:转载
供稿:网友

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

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

1.anin_searh.xml

<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android"   android:oneshot="true">  <item android:drawable="@drawable/a1" android:duration="100"></item>   <item android:drawable="@drawable/a2" android:duration="100"></item>   <item android:drawable="@drawable/a4" android:duration="100"></item>   <item android:drawable="@drawable/a5" android:duration="100"></item>   <item android:drawable="@drawable/a6" android:duration="100"></item>   <item android:drawable="@drawable/a7" android:duration="100"></item>   <item android:drawable="@drawable/a8" android:duration="100"></item>   <item android:drawable="@drawable/a9" android:duration="100"></item>   <item android:drawable="@drawable/a10" android:duration="100"></item>   <item android:drawable="@drawable/a11" android:duration="100"></item> </animation-list> 

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<MyFrame> 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<MyFrame> 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<MyFrame> myFrames = new ArrayList<MyFrame>();          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<MyFrame> myFrames,                       ImageView imageView, Runnable onComplete) {     animateRawManually(myFrames, imageView, onComplete, 0);   }    // 5   private static void animateRawManually(final List<MyFrame> 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");                                }             }); 

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

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表