当前位置: 移动技术网 > IT编程>移动开发>Android > Android 使用帧动画内存溢出解决方案

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

火爆龙的妙管家,梁夏银个人资料,深圳社保电脑号查询

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"); 
                 
              } 
            }); 

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

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网